栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springboot集成shiro使用JWT做登录验证

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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);

    
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        HttpServletRequest req = (HttpServletRequest) request;
        String authorization = req.getHeader("Authorization");
        return authorization != null;
    }

    
    @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;
    }

    
    @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;
    }


    
    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
 
    @Bean()
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);


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

        Map 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
欢迎指正不足,共同进步

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/338071.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号