美文网首页Java
Spring Boot集成MyBatis、Redis、JWT、S

Spring Boot集成MyBatis、Redis、JWT、S

作者: Cool_Pomelo | 来源:发表于2020-06-09 19:49 被阅读0次

    Spring Boot集成MyBatis、Redis、JWT、Shiro

    认证流程

    图1.png

    自定义过滤器

    
    @Slf4j
    public class JwtFilter extends BasicHttpAuthenticationFilter {
    
        /**
         * 执行登录认证
         *
         * @param request
         * @param response
         * @param mappedValue
         * @return
         */
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
            log.info("进入  JwtFilter 的 isAccessAllowed 方法 ");
            try {
                executeLogin(request, response);
                return true;
            } catch (Exception e) {
                throw new AuthenticationException("Token失效请重新登录");
            }
        }
    
        @Override
        protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
            log.info("进入  JwtFilter 的 executeLogin 方法 ");
    
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            String token = httpServletRequest.getHeader(CommonConstant.ACCESS_TOKEN);
            JwtToken jwtToken = new JwtToken(token);
            // 提交给realm进行登入,如果错误他会抛出异常并被捕获
            getSubject(request, response).login(jwtToken);
            // 如果没有抛出异常则代表登入成功,返回true
            return true;
        }
    
        /**
         * 对跨域提供支持
         */
        @Override
        protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
            log.info("进入  JwtFilter 的 preHandle 方法 ");
            
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
            httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
            httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
            // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
            if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
                httpServletResponse.setStatus(HttpStatus.OK.value());
                return false;
            }
            return super.preHandle(request, response);
        }
    }
    
    

    自定义Realm

    @Component
    @Slf4j
    public class ShiroRealm extends AuthorizingRealm {
    
        @Autowired
        @Lazy
        private ISysUserService sysUserService;
        @Autowired
        @Lazy
        private RedisUtil redisUtil;
    
        /**
         * 必须重写此方法,不然Shiro会报错
         */
        @Override
        public boolean supports(AuthenticationToken token) {
            return token instanceof JwtToken;
        }
    
        /**
         * 功能: 获取用户权限信息,包括角色以及权限。只有当触发检测用户权限时才会调用此方法,例如checkRole,checkPermission
         *
         * @param principals token
         * @return AuthorizationInfo 权限信息
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            log.info("进入 ShiroRealm 的 doGetAuthorizationInfo方法");
            log.info("————权限认证 [ roles、permissions]————");
            SysUser sysUser = null;
            String username = null;
            if (principals != null) {
                sysUser = (SysUser) principals.getPrimaryPrincipal();
                username = sysUser.getUserName();
            }
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
            // 设置用户拥有的角色集合,比如“admin,test”
            Set<String> roleSet = sysUserService.getUserRolesSet(username);
            info.setRoles(roleSet);
    
            // 设置用户拥有的权限集合,比如“sys:role:add,sys:user:add”
            Set<String> permissionSet = sysUserService.getUserPermissionsSet(username);
            info.addStringPermissions(permissionSet);
            return info;
        }
    
        /**
         * 功能: 用来进行身份认证,也就是说验证用户输入的账号和密码是否正确,获取身份验证信息,错误抛出异常
         *
         * @param auth 用户身份信息 token
         * @return 返回封装了用户信息的 AuthenticationInfo 实例
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
    
            log.info("进入 ShiroRealm 的 doGetAuthenticationInfo");
            
            String token = (String) auth.getCredentials();
            if (token == null) {
                log.info("————————身份认证失败——————————IP地址:  " + CommonUtils.getIpAddrByRequest(SpringContextUtils.getHttpServletRequest()));
                throw new AuthenticationException("token为空!");
            }
            // 校验token有效性
            SysUser loginUser = this.checkUserTokenIsEffect(token);
    
            log.info("执行完毕 ShiroRealm 的 doGetAuthenticationInfo");
    
            return new SimpleAuthenticationInfo(loginUser, token, getName());
        }
    
        /**
         * 校验token的有效性
         *
         * @param token
         */
        public SysUser checkUserTokenIsEffect(String token) throws AuthenticationException {
    
            log.info("进入 ShiroRealm 的 checkUserTokenIsEffect");
    
    
    
            // 解密获得username,用于和数据库进行对比
            String username = JwtUtil.getUsername(token);
            if (username == null) {
                throw new AuthenticationException("token非法无效!");
            }
    
            // 查询用户信息
            SysUser loginUser = new SysUser();
            SysUser sysUser = sysUserService.getUserByName(username);
            if (sysUser == null) {
                throw new AuthenticationException("用户不存在!");
            }
    
            // 校验token是否超时失效 & 或者账号密码是否错误
            if (!jwtTokenRefresh(token, username, sysUser.getPassWord())) {
                log.info("Token失效请重新登录Token失效请重新登录Token失效请重新登录Token失效请重新登录");
                throw new AuthenticationException("Token失效请重新登录!");
            }
    
    //        // 判断用户状态
    //        if (!"0".equals(sysUser.getDelFlag())) {
    //            throw new AuthenticationException("账号已被删除,请联系管理员!");
    //        }
    
            BeanUtils.copyProperties(sysUser, loginUser);
            log.info("执行完毕 ShiroRealm 的 checkUserTokenIsEffect");
    
            return loginUser;
        }
    
        /**
         *
         * @param userName
         * @param passWord
         * @return
         */
        public boolean jwtTokenRefresh(String token, String userName, String passWord) {
    
            log.info("进入 ShiroRealm 的 jwtTokenRefresh");
    
    
    
            String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + userName));
            if (CommonUtils.isNotEmpty(cacheToken)) {
                // 校验token有效性
                if (!JwtUtil.verify(cacheToken, userName, passWord)) {
                    log.info("进入 jwtTokenRefresh {}{}   verify ");
                    String newAuthorization = JwtUtil.sign(userName, passWord);
                    redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + userName, newAuthorization);
                    // 设置超时时间
                    redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + userName, JwtUtil.EXPIRE_TIME / 1000);
                } else {
                    log.info(" jwtTokenRefresh>>>>>>>>>>>else");
                    redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + userName, cacheToken);
                    // 设置超时时间
                    redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + userName, JwtUtil.EXPIRE_TIME / 1000);
                }
                return true;
            }
    
            log.info("执行完毕 ShiroRealm 的 jwtTokenRefresh");
    
            return false;
        }
    
    }
    
    

    shiro 配置类

    public class ShiroConfig {
    
    
        @Bean("shiroFilter")
        public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            // 拦截器
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
            // 配置不会被拦截的链接 顺序判断
            filterChainDefinitionMap.put("/sys/login", "anon"); //登录接口排除
            filterChainDefinitionMap.put("/sys/logout", "anon"); //登出接口排除
            filterChainDefinitionMap.put("/sys/register", "anon"); //登出接口排除
    
            filterChainDefinitionMap.put("/", "anon");
            filterChainDefinitionMap.put("/**/*.js", "anon");
            filterChainDefinitionMap.put("/**/*.css", "anon");
            filterChainDefinitionMap.put("/**/*.html", "anon");
            filterChainDefinitionMap.put("/**/*.jpg", "anon");
            filterChainDefinitionMap.put("/**/*.png", "anon");
            filterChainDefinitionMap.put("/**/*.ico", "anon");
    
            filterChainDefinitionMap.put("/druid/**", "anon");
            filterChainDefinitionMap.put("/user/test", "anon"); //测试
    
            // 添加自己的过滤器并且取名为jwt
            Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
            filterMap.put("jwt", new JwtFilter());
            shiroFilterFactoryBean.setFilters(filterMap);
            filterChainDefinitionMap.put("/**", "jwt");
    
            shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403");
            shiroFilterFactoryBean.setLoginUrl("/sys/common/403");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
        @Bean("securityManager")
        public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(myRealm);
            DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
            DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
            defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
            subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
            securityManager.setSubjectDAO(subjectDAO);
    
            return securityManager;
        }
    
        /**
         * 下面的代码是添加注解支持
         *
         * @return
         */
        @Bean
        @DependsOn("lifecycleBeanPostProcessor")
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
            return defaultAdvisorAutoProxyCreator;
        }
    
        @Bean
        public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }
    
    }
    
    

    PostMan测试

    图2.png 图3.png

    相关文章

      网友评论

        本文标题:Spring Boot集成MyBatis、Redis、JWT、S

        本文链接:https://www.haomeiwen.com/subject/khqizhtx.html