IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> springboot集成shiro使用JWT做登录验证 -> 正文阅读

[Java知识库]springboot集成shiro使用JWT做登录验证

shiro是使用session验证登录状态,想使用JWT为登录验证,只需要重写shiro的登录后的验证过滤器就能使用JWT

继承BasicHttpAuthenticationFilter过滤器,重写该类中的方法

import com.alibaba.fastjson.JSON;
import com.project.User.entity.Result;
import com.project.config.JWTToken;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpStatus;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


public class JWTFilter extends BasicHttpAuthenticationFilter {

    //设置请求头中需要传递的字段名
    protected static final String AUTHORIZATION_HEADER = "Authorization";
    private static final Logger log = LogManager.getLogger(JWTFilter.class);

    /**
     * 判断用户是否想要登入。
     * 检测header里面是否包含Authorization字段即可
     * <p>
     * * Controller中可以通过 subject.isAuthenticated() 来判断用户是否登入
     * * 如果有些资源只有登入用户才能访问,我们只需要在 Controller 或者 method 上面加上 @RequiresAuthentication 注解
     * </p>
     */
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        HttpServletRequest req = (HttpServletRequest) request;
        String authorization = req.getHeader("Authorization");
        return authorization != null;
    }

    /**
     * 认证之前执行该方法
     *
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        Subject subject = SecurityUtils.getSubject();
        return null != subject && subject.isAuthenticated();
//        if (isLoginAttempt(request, response)) {
//            try {
//                executeLogin(request, response);
//            } catch (Exception e) {
//                response401(response, e.getMessage());
//            }
//        }
//        return true;
    }

    /**
     * 执行登入
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String authorization = httpServletRequest.getHeader(AUTHORIZATION_HEADER);

        JWTToken token = new JWTToken(authorization);
        // 提交给realm进行登入,如果错误他会抛出异常并被捕获
        getSubject(request, response).login(token);
        // 如果没有抛出异常则代表登入成功,返回true
        return true;
    }

    /**
     * 认证未通过执行该方法
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        if ("OPTIONS".equals(httpServletRequest.getMethod())){
            return true;
        }
        //完成token登入
        //1.检查请求头中是否含有token
        String token = httpServletRequest.getHeader(AUTHORIZATION_HEADER);
        //2. 如果客户端没有携带token,拦下请求
        if (null == token || "".equals(token)) {
            response401(response, "认证失败(Unauthorized),无法访问系统资源");
            return false;
        }
        //3. 委托给Realm进行token验证
        JWTToken jwtToken = new JWTToken(token);
        try {
            SecurityUtils.getSubject().login(jwtToken);
        } catch (AuthenticationException e) {
            log.error(e.getMessage());
            response401(response, e.getMessage());
            return false;
        }

        return true;
    }


    /**
     * 直接返回Response信息
     */
    private void response401(ServletResponse response, String msg) {
        HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
        httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json; charset=utf-8");
        try (PrintWriter out = httpServletResponse.getWriter()) {
            String data = JSON.toJSONString(Result.error(HttpStatus.UNAUTHORIZED.value(), msg, null));
            out.append(data);
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
    }

Realm中,认证方法借鉴

 @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        boolean verify = jwtUtil.verify(token);
        if (!verify) {
            throw new AuthenticationException("token无效,请重新登录");
        }
        // 验证通过,解密获得username,用于和数据库进行对比
        Integer userid = jwtUtil.getIntUser(token,"userid");
        if (userid == null) {
            throw new AuthenticationException("token无效");
        }
        String redisToken =(String) redisTemplate.opsForValue().get(RedisPreloadData.LOGIN_TOKEN_BYID + userid);
        if(!redisToken.equals(token)){throw new AuthenticationException("已退出登录或其他地方已登录,令牌无效");}
        Object redisUserid = redisTemplate.opsForValue().get(RedisPreloadData.LOGIN_USER_INFO + userid);
        if (redisUserid == null) {
            throw new AuthenticationException("用户不存在");
        }

        return new SimpleAuthenticationInfo(token, token, this.getName());
    }

登录过滤器写好后,还需要在shiro的配置文件中添加该过滤器,ShiroConfig.java

 /**
     * shiro 过滤器
     *
     * @param securityManager
     * @return
     */
    @Bean()
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);


        // 添加自己的过滤器并且取名为jwt
        //自定义权限拦截器roles
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JWTFilter());
       // filterMap.put("roles", new CustomisedURLPathMatchingFilter());
        factoryBean.setFilters(filterMap);

        Map<String, String> filterRuleMap = new HashMap<>();
        //所有路径都被权限及jwt过滤器捕获
        filterRuleMap.put("/**", "noSessionCreation,jwt,roles");
        // 访问401和404页面不通过我们的Filter
        filterRuleMap.put("/404", "anon");
        filterRuleMap.put("/druid/**", "anon");
        filterRuleMap.put("/swagger-ui.html/**", "anon");
        filterRuleMap.put("/webjars/**", "anon");
        filterRuleMap.put("/swagger-resources/**", "anon");
        filterRuleMap.put("/configuration/security", "anon");
        filterRuleMap.put("/configuration/ui", "anon");
        filterRuleMap.put("/v2/api-docs", "anon");
        filterRuleMap.put("/land/common/kaptcha", "anon");
        filterRuleMap.put("/land/login", "anon");
        filterRuleMap.put("/land/logout", "anon");

        factoryBean.setFilterChainDefinitionMap(filterRuleMap);
        return factoryBean;
    }

注意:shiro配置文件中放行的map顺序不能乱排,按照放心或拦截顺序写

看完整实例代码
码云:https://gitee.com/hydrogenated-oxygen/erpshiro
欢迎指正不足,共同进步

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-20 12:21:41  更:2021-10-20 12:22:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:19:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码