zoukankan      html  css  js  c++  java
  • shiro+jwt 实现权限控制

    一.导入shiro和jwt的包

    <jwt.version>3.4.0</jwt.version>
    <shiro.version>1.3.2</shiro.version>
    <!-- JWT -->
    <dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>${jwt.version}</version>
    </dependency>
    <!-- Shiro -->
    <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>${shiro.version}</version>
    </dependency>

    二.数据库表结构
    1.用户表:sys_amdin

     2.角色表:sys_role

     3.用户角色中间表:sys_amdin_role

     4.权限表:sys_permission

    5. 角色权限中间表:sys_role_permission

    三.jwt工具类(token加密解密)JwtUtilAdmin

    在配置文件里定义三个变量

    accessTokenExpireTime=2592000
    refreshTokenExpireTime=31104000
    shiroCacheExpireTime=31104000
    @Component
    public class JwtUtilAdmin {
    
        /**
         * LOGGER
         */
        private static final Logger LOGGER = LoggerFactory.getLogger(JwtUtilAdmin.class);
        /**
         * 过期时间改为从配置文件获取
         */
        private static String accessTokenExpireTime;
        
        private static Integer shiroCacheExpireTime;
        /**
         * JWT认证加密私钥(Base64加密)
         */
        private static String encryptJWTKey;
    
        @Value("${accessTokenExpireTime}")
        public void setAccessTokenExpireTime(String accessTokenExpireTime) {
            JwtUtilAdmin.accessTokenExpireTime = accessTokenExpireTime;
        }
        
        @Value("${shiroCacheExpireTime}")
        public void setShiroCacheExpireTime(Integer shiroCacheExpireTime) {
            JwtUtilAdmin.shiroCacheExpireTime = shiroCacheExpireTime;
        }
        @Value("${encryptJWTKey}")
        public void setEncryptJWTKey(String encryptJWTKey) {
            JwtUtilAdmin.encryptJWTKey = encryptJWTKey;
        }
        /**
         * 校验token是否正确
         * 
         * @param token
         *            Token
         * @return boolean 是否正确
         */
        public static boolean verify(String token) {
            try {
                // 帐号加JWT私钥解密
                String secret = getClaim(token, Constant.ACCOUNT) +  Base64.decodeStr(encryptJWTKey, "utf-8");
                Algorithm algorithm = Algorithm.HMAC256(secret);
                JWTVerifier verifier = JWT.require(algorithm)./*acceptExpiresAt(20).*/build();
                DecodedJWT jwt = verifier.verify(token);
                return true;
            } catch (JWTDecodeException e) {
                LOGGER.error("JWTToken认证解密出现UnsupportedEncodingException异常:" + e.getMessage());
                throw new CustomException("JWTToken认证解密出现UnsupportedEncodingException异常:" + e.getMessage());
            }
        }
        /**
         * 获得Token中的信息无需secret解密也能获得
         * 
         * @param token
         * @param claim
         * @return java.lang.String
         */
        public static String getClaim(String token, String claim) {
            try {
                DecodedJWT jwt = JWT.decode(token);
                // 只能输出String类型,如果是其他类型返回null
                return jwt.getClaim(claim).asString();
            } catch (JWTDecodeException e) {
                LOGGER.error("解密Token中的公共信息出现JWTDecodeException异常:" + e.getMessage());
                throw new CustomException("解密Token中的公共信息出现JWTDecodeException异常:" + e.getMessage());
            }
        }
        /**
         * 生成签名
         * 
         * @param account
         *            帐号
         * @return java.lang.String 返回加密的Token
         * @throws  
         */
        public static String sign(String account, String currentTimeMillis)  {
            try {
                // 帐号加JWT私钥加密
                String secret = account + Base64.decodeStr(encryptJWTKey, "utf-8");
                // 此处过期时间是以毫秒为单位,所以乘以1000
                Date date = new Date(System.currentTimeMillis() + Long.parseLong(accessTokenExpireTime) * 1000);
                Algorithm algorithm = Algorithm.HMAC256(secret);
                // 附带account帐号信息
                return JWT.create().withClaim(Constant.ACCOUNT, account).withClaim(Constant.CURRENT_TIME_MILLIS, currentTimeMillis)
                        .withExpiresAt(date).sign(algorithm);
            } catch (JWTCreationException e) {
                LOGGER.error("JWTToken加密出现IllegalArgumentException异常:" + e.getMessage());
                throw new CustomException("JWTToken加密出现IllegalArgumentException异常:" + e.getMessage());
            }
        }
        
        /**
         * 生成签名(业务员,门店账号)
         * @param account  帐号
         * @return java.lang.String 返回加密的Token
         */
        public static String signOther(String account, String currentTimeMillis) {
            try {
                // 帐号加JWT私钥加密
                String secret = account + Base64.decode(encryptJWTKey);
                // 此处过期时间是以毫秒为单位,所以乘以1000
                Date date = new Date(System.currentTimeMillis() + shiroCacheExpireTime *24*60*60*1000l);
                Algorithm algorithm = Algorithm.HMAC256(secret);
                // 附带account帐号信息
                return JWT.create().withClaim(Constant.ACCOUNT, account).withClaim(Constant.CURRENT_TIME_MILLIS/*"currentTimeMillis"*/, currentTimeMillis)
                        .withExpiresAt(date).sign(algorithm);
            } catch (JWTDecodeException e) {
                LOGGER.error("JWTToken加密出现UnsupportedEncodingException异常:" + e.getMessage());
                throw new CustomException("JWTToken加密出现UnsupportedEncodingException异常:" + e.getMessage());
            }
        }
    }

    四.账号密码登录实现类

     @Override
        public BaseResponse<?> loginPassword(String account, String password) {
            //交于自定义的UserRealm校验
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(account, password, password);
            SecurityUtils.getSubject().login(usernamePasswordToken);
            //登录成功返回vo
            SysAdmin admin = new SysAdmin();
            admin.setAccount(account);
            admin.setState(AdminStateEnum.USABLE.getCode());
            List<SysAdmin> admins = this.baseMapper.select(admin);
            admin = admins.get(0);
            AdminLoginVo adminLoginVo = getAdminLoginVo(admin);
            adminLoginVo.setAdminId(admin.getId());
            if( adminLoginVo.getClinicId() == null){
                return BaseResponse.error("诊所信息有误");
            }
            if(!RoleStateEnum.USABLE.getCode().equals(adminLoginVo.getRoleState()) || adminLoginVo.getRoleId() == null){
                return BaseResponse.error("角色未启用");
            }
            //由于http的session不便于测试故舍弃,用security的session
            Session session = SecurityUtils.getSubject().getSession();
            loginSuccess(session, admin.getId(), adminLoginVo);
            return BaseResponse.success(adminLoginVo);
        }
        //登录成功,将用户信息存入session,redis并返回
        private void loginSuccess(Session session, Integer adminId, AdminLoginVo adminLoginVo){
            //登录用户ID加密得到token
            String token = JwtUtilAdmin.sign(adminId.toString(), System.currentTimeMillis() + "");
            //登录成功返回token
            adminLoginVo.setToken(token);
            //永久保存
            session.setTimeout(-1);
            session.setAttribute(Constant.CURRENT_USER, adminLoginVo);
            //以ID为key, 当前时间为value存进redis
            iRedisService.set(KeyUtil.LOGIN_KEY + token, adminLoginVo, 24 * 60 * 60 * 30 * 36);
        }
        //得到登录返回的AdminLoginVo
        private AdminLoginVo getAdminLoginVo(SysAdmin admin){
            Clinic clinic = iClinicService.selectById(admin.getClinicId());
            SysRole sysRole = iSysRoleService.selectByAdminId(admin.getId());
            AdminLoginVo adminLoginVo = new AdminLoginVo(admin.getState(), admin.getAuthState());
            adminLoginVo.setClinicId(admin.getClinicId());
            adminLoginVo.setRoleType(admin.getClinicId());
            adminLoginVo.setRoleTypeName(RoleTypeNameUtil.getRoleTypeName(adminLoginVo.getRoleType()
                    , adminLoginVo.getRoleTypeName()));
            if(clinic != null){
                adminLoginVo.setClinicName(clinic.getClinicName());
                adminLoginVo.setClinicId(clinic.getId());
            }
            if(sysRole != null){
                adminLoginVo.setRoleName(sysRole.getRoleName());
                adminLoginVo.setRoleId(sysRole.getId());
                adminLoginVo.setRoleState(sysRole.getState());
            }
            return adminLoginVo;
        }

    五.自定义shiroConfig

    首先创建JwtFilterAdmin过滤

    public class JwtFilterAdmin extends BasicHttpAuthenticationFilter {
        /**
         * LOGGER
         */
        private static final Logger LOGGER = LoggerFactory.getLogger(JwtFilterAdmin.class);
    
        private IRedisService redisService;
        {
    
        }
    
        /**
         * 这里我们详细说明下为什么最终返回的都是true,即允许访问
         * 例如我们提供一个地址 GET /article
         * 登入用户和游客看到的内容是不同的
         * 如果在这里返回了false,请求会被直接拦截,用户看不到任何东西
         * 所以我们在这里返回true,Controller中可以通过 subject.isAuthenticated() 来判断用户是否登入
         * 如果有些资源只有登入用户才能访问,我们只需要在方法上面加上 @RequiresAuthentication 注解即可
         * 但是这样做有一个缺点,就是不能够对GET,POST等请求进行分别过滤鉴权(因为我们重写了官方的方法),但实际上对应用影响不大
         */
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
            // 查看当前Header中是否携带Authorization属性(Token),有的话就进行登录认证授权
            if (this.isLoginAttempt(request, response)) {
                try {
                    // 进行Shiro的登录UserRealm
                    this.executeLogin(request, response);
                } catch (Exception e) {
                    // 认证出现异常,传递错误信息msg
                    String msg = e.getMessage();
                    // 获取应用异常(该Cause是导致抛出此throwable(异常)的throwable(异常))
                    Throwable throwable = e.getCause();
                    if (throwable instanceof SignatureVerificationException) {
                        // 该异常为JWT的AccessToken认证失败(Token或者密钥不正确)
                        msg = "Token或者密钥不正确(" + throwable.getMessage() + ")";
                    } else if (throwable instanceof TokenExpiredException) {
                        // 该异常为JWT的AccessToken已过期,判断RefreshToken未过期就进行AccessToken刷新
                        try{
                            if (this.refreshToken(request, response)) {
                                return true;
                            } else {
                                msg = "Token已过期(" + throwable.getMessage() + ")";
                            }
                        }catch(Exception ex){
                             msg = "Token已过期(" + ex + ")";
                        }
                    } else {
                        // 应用异常不为空
                        if (throwable != null) {
                            // 获取应用异常msg
                            msg = throwable.getMessage();
                        }
                    }
                    /*
                      错误两种处理方式
                      1. 将非法请求转发到/401的Controller处理,抛出自定义无权访问异常被全局捕捉再返回Response信息
                      2. 无需转发,直接返回Response信息
                      一般使用第二种(更方便)
                     */
                    // 直接返回Response信息
                    this.response401(response, msg);
                    return false;
                }
            } else {
                // 没有携带Token
                HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
                // 获取当前请求类型
                String httpMethod = httpServletRequest.getMethod();
                // 获取当前请求URI
                String requestURI = httpServletRequest.getRequestURI();
                LOGGER.info("当前请求 {} Authorization属性(Token)为空 请求类型 {}", requestURI, httpMethod);
                // mustLoginFlag = true 开启任何请求必须登录才可访问
                Boolean mustLoginFlag = false;  //开启h5页面不能访问?
                if (mustLoginFlag) {
                    this.response401(response, "请先登录");
                    return false;
                }
            }
            return true;
        }
    
        /**
         * 这里我们详细说明下为什么重写
         * 可以对比父类方法,只是将executeLogin方法调用去除了
         * 如果没有去除将会循环调用doGetAuthenticationInfo方法
         */
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
            this.sendChallenge(request, response);
            return false;
        }
    
        /**
         * 检测Header里面是否包含Authorization字段,有就进行Token登录认证授权
         */
        @Override
        protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
            // 拿到当前Header中Authorization的AccessToken(Shiro中getAuthzHeader方法已经实现)
            //String token = this.getAuthzHeader(request);
            String token = WebUtils.toHttp(request).getHeader("token");
            return StringUtils.isNotBlank(token);
        }
    
        /**
         * 进行AccessToken登录认证授权
         */
        @Override
        protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
            String tokenStr = WebUtils.toHttp(request).getHeader("token");
            LOGGER.info("获得header里的token= {}", tokenStr);
            JwtTokenAdmin token = new JwtTokenAdmin(tokenStr);
            // 提交给UserRealm进行认证,如果错误他会抛出异常并被捕获
            this.getSubject(request, response).login(token);
            // 如果没有抛出异常则代表登入成功,返回true
            return true;
        }
    
        /**
         * 对跨域提供支持
         */
        @Override
        protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
            HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
            HttpServletResponse httpServletResponse = WebUtils.toHttp(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"));
            // 跨域时会首先发送一个OPTIONS请求,这里我们给OPTIONS请求直接返回正常状态
            if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
                httpServletResponse.setStatus(HttpStatus.OK.value());
                return false;
            }
            return super.preHandle(request, response);
        }
    
        /**
         * 此处为AccessToken刷新,进行判断RefreshToken是否过期,未过期就返回新的AccessToken且继续正常访问
         */
        private boolean refreshToken(ServletRequest request, ServletResponse response) {
            String token = WebUtils.toHttp(request).getHeader("token");
            // 获取当前Token的帐号信息
            String account = JwtUtilAdmin.getClaim(token, Constant.ACCOUNT);
    
            Map<String, String> oldTokenMap = redisService.hmget(Constant.PREFIX_SHIRO_REFRESH_TOKEN + account);
            String refreshExpireTime = oldTokenMap.get(token);
            if (refreshExpireTime != null) {
                String key = KeyUtil.keyOf(KeyUtil.TRY_LOCK, account);
                try{
                    if(redisService.tryLock(key)){  //控制异步并发请求
                        String newToken = refreshToken(account);
                        if(newToken == null) {
                            return false;
                        }
                        JwtTokenAdmin jwtTokenAdmin = new JwtTokenAdmin(newToken);
                        this.getSubject(request, response).login(jwtTokenAdmin);
                        LOGGER.info("旧的token={}被新token{}替换", token, newToken);
                        return true;
                    }
                }finally{
                    redisService.remove(key);
                }
            }
            return true;
        }
    
    
        /**
         * token 过期 才能用
         * @param id
         */
        public String refreshToken(String id){
            //过期token
            String old = Constant.PREFIX_SHIRO_OLD_TOKEN + id;
            //当前token
            String current = Constant.PREFIX_SHIRO_REFRESH_TOKEN + id;
            Map<String, String> map = null;
            if(redisService.exsits(old)) {    //当前token已过期,并且token已刷新, 返回刷新过的新token
                map = redisService.hmget(Constant.PREFIX_SHIRO_REFRESH_TOKEN + id);
                for(String token : map.keySet()) {
                    return token;
                }
                return null;
            }else {
                //刷新token
                String currentTimeMillis = String.valueOf(System.currentTimeMillis());
                String token = JwtUtilAdmin.sign(id, currentTimeMillis);   //accessExpireTime
                try{
                    map = redisService.hmget(Constant.PREFIX_SHIRO_REFRESH_TOKEN + id);
                    map.put(token, currentTimeMillis);
                }catch(Exception e){
                    map = Maps.newHashMap();
                    map.put(token, currentTimeMillis);
                }
                //30天 超时时间
                String refreshTokenExpireTime = SpringContextUtil.getEnvironmentProperty("refreshTokenExpireTime");
                redisService.hmset(Constant.PREFIX_SHIRO_REFRESH_TOKEN + id, map, Integer.parseInt(refreshTokenExpireTime));
                return token;
            }
        }
        /**
         * 无需转发,直接返回Response信息
         */
        private void response401(ServletResponse response, String msg) {
            LOGGER.info("3" + Thread.currentThread().getName());
            HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
            httpServletResponse.setStatus(HttpStatus.OK.value());
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json; charset=utf-8");
            try (PrintWriter out = httpServletResponse.getWriter()) {
                Map<Integer, String> result = Maps.newHashMap();
                result.put(401, "无权访问,请重新登录");
                String data = JSON.toJSONString(result);
                out.append(data);
            } catch (IOException e) {
                LOGGER.error("直接返回Response信息出现IOException异常:" + e.getMessage());
                throw new CustomException("直接返回Response信息出现IOException异常:" + e.getMessage());
            }
        }
        
        private void setResponseheader(String token, ServletResponse response){
            // 最后将刷新的AccessToken存放在Response的Header中的Authorization字段返回
            HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
            httpServletResponse.setHeader("Authorization", token);
            httpServletResponse.setHeader("Access-Control-Expose-Headers", "Authorization");
        }
    }

    在shiroConfig里调用我们创建的jwt拦截规则

    @Configuration
    public class ShiroConfig {
    
        /**
         * 配置使用自定义Realm,关闭Shiro自带的session 详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-
         * StatelessApplications%28Sessionless%29
         *
         * @param userRealm
         */
        @Bean("securityManager")
        public DefaultWebSecurityManager defaultWebSecurityManager(MyRealmAdmin userRealm) {
            DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
            // 使用自定义Realm
            defaultWebSecurityManager.setRealm(userRealm);
            // 关闭Shiro自带的session
            DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
            DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
            defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
            subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
            defaultWebSecurityManager.setSubjectDAO(subjectDAO);
            // 设置自定义Cache缓存
            defaultWebSecurityManager.setCacheManager(new CustomCacheManager());
            return defaultWebSecurityManager;
        }
    
        @Bean("shiroFilter")
        public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
            ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
            // 添加自己的过滤器取名为jwt
            Map<String, Filter> filterMap = new HashMap<>(16);
            filterMap.put("jwt", new JwtFilterAdmin());
            factoryBean.setFilters(filterMap);
            factoryBean.setSecurityManager(securityManager);
            /**
             * anon:无需认证
             * authc:必须认证
             * user:如果使用rememberMe可直接访问
             * perms:该资源必须得到资源权限才可以访问
             * role:该资源必须得到资源权限才可以访问
             */
            // 自定义url规则使用LinkedHashMap有序Map
            LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(16);
            //登录
            filterChainDefinitionMap.put("/login/*", "anon");
            //获取验证码
            filterChainDefinitionMap.put("/phone/code", "anon");
            //获取角色类型
            filterChainDefinitionMap.put("/role/type", "anon");
            //无权限异常
            filterChainDefinitionMap.put("/exception/getException", "anon");
            //上传图片/文件
            filterChainDefinitionMap.put("/img/getUrl", "anon");
            //jwt拦截
            filterChainDefinitionMap.put("/**", "jwt");
            factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return factoryBean;
        }
        /**
         * 下面的代码是添加注解支持
         */
        @Bean
        @DependsOn("lifecycleBeanPostProcessor")
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            // 强制使用cglib,防止重复代理和可能引起代理出错的问题,https://zhuanlan.zhihu.com/p/29161098
            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; } }
    六.自定义userRealm
    public abstract class MyRealmAdmin extends AuthorizingRealm {
    
    
    }
    @Service
    public class UserRealm extends MyRealmAdmin {
    
        @Autowired
        private IRedisService iRedisService;
    
        @Autowired
        private ISysAdminService iSysAdminService;
        @Autowired
        private ISysRoleService iSysRoleService;
        @Autowired
        private ISysPermissionService iSysPermissionService;
    
        @Autowired
        private IClinicService iClinicService;
    
        @Override
        public boolean supports(AuthenticationToken authenticationToken) {
            return authenticationToken instanceof JwtTokenAdmin || authenticationToken instanceof UsernamePasswordToken;
        }
    
        /**
         * 只有当需要检测用户权限的时候才会调用此方法,例如checkRole,checkPermission之类的
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            String account = JwtUtilAdmin.getClaim(principalCollection.toString(), Constant.ACCOUNT);
            SysAdmin userDto = new SysAdmin();
            userDto.setId(Integer.valueOf(account));
            // 查询用户角色
            SysRole roleDto = iSysRoleService.selectByAdminId(Integer.valueOf(account));
            if (roleDto != null) {
                // 根据用户角色查询权限
                List<SysPermission> permissionDtos = iSysPermissionService.selectByRoleId(roleDto.getId());
                for (SysPermission permissionDto : permissionDtos) {
                    if (permissionDto != null && StringUtils.isNotBlank(permissionDto.getPermissionStr())) {
                        // 添加权限
                        simpleAuthorizationInfo.addStringPermission(permissionDto.getPermissionStr());
                    }
                }
            }
            return simpleAuthorizationInfo;
        }
    
        /**
         * 默认使用此方法进行用户名正确与否验证,错误抛出异常即可。
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)  throws AuthenticationException {
            if(authenticationToken instanceof UsernamePasswordToken){
                UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
                String account = token.getUsername();
                String password = token.getHost();
                //账号密码登录校验
                SysAdmin admin = new SysAdmin();
                admin.setAccount(account);
                admin.setState(AdminStateEnum.USABLE.getCode());
                List<SysAdmin> admins = iSysAdminService.select(admin);
                if(admins.size() == 0){
                    throw new AuthenticationException("账号不存在");
                }
                if(admins.size() > 1){
                    throw new AuthenticationException("账号信息有误");
                }
                admin = admins.get(0);
                if(!admin.getPassword().equals(MD5Util.MD5SaltEncodeing(password))){
                    throw new AuthenticationException("密码错误,请重新填写");
                }
                if(!AdminAuthStateEnum.PASS.getCode().equals(admin.getAuthState())){
                    throw new AuthenticationException(AdminAuthStateEnum.valueOfCode(admin.getAuthState()).getMessage());
                }
                return new SimpleAuthenticationInfo(token, password, account);
            }else {
                //调用其它接口时token校验
                Object credential = authenticationToken.getCredentials();
                if(credential == null){
                    throw new AuthenticationException("Token为空(The Token is empty.)");
                }
                String token = credential.toString();
    
                // 解密获得account,用于和数据库进行对比
                if (JwtUtilAdmin.verify(token)) {
                    String account = JwtUtilAdmin.getClaim(token, Constant.ACCOUNT);
                    if (StringUtil.isBlank(account)) {
                        throw new AuthenticationException("Token中帐号为空(The account in Token is empty.)");
                    }
                    AdminLoginVo adminLoginVo = iRedisService.get(KeyUtil.LOGIN_KEY + token, AdminLoginVo.class);
                    if (adminLoginVo != null) {
                        SysAdmin sysAdmin = iSysAdminService.selectById(Integer.valueOf(account));
                        if (sysAdmin == null) {
                            throw new AuthenticationException("该帐号不存在(The account does not exist.)");
                        }
                        if(!RoleTypeEnum.USABLE.getCode().equals(adminLoginVo.getRoleType())){
                            Clinic  clinic =  iClinicService.selectById(sysAdmin.getClinicId());
                            if(!Constant.ZERO.equals(clinic.getState())) {
                                switch (clinic.getState()) {
                                    case 10:   throw new AuthenticationException("该诊所已被禁用");
                                    case 20:   throw new AuthenticationException("该诊所正在审核中");
                                    case 30:   throw new AuthenticationException("该诊所审核失败");
                                    default:   break;
                                }
                            }
                        }
                        return new SimpleAuthenticationInfo(token, token, account);
                    }
                }
                throw new AuthenticationException("Token已过期(Token expired or incorrect.)");
            }
        }
    }

    七.JwtTokenAdmin 

    public class JwtTokenAdmin implements AuthenticationToken {
        private static final long serialVersionUID = 960867003694917627L;
        /**
         * Token
         */
        private String token;
    
        public JwtTokenAdmin(String token) {
            this.token = token;
        }
    
        @Override
        public Object getPrincipal() {
            return token;
        }
    
        @Override
        public Object getCredentials() {
            return token;
        }
    }
    八.关于授权
    在接口上加入注解, 引号内为菜单标识, 需存入权限表sys_permission 的permission_str字段里
    @RequiresPermissions("super:admin:list")

    sys_permission:

     sys_role_permission:

     sys_role:

    sys_admin_role:

     sys_admin:

    接口代码:
       /**
        * @description: //:超级管理员列表
        * @auth onfec
        * @param keyWord 根据账号, 姓名, 手机号模糊查询
        * @return com.sysf.doc.BaseResponse<?>
        * @date 2020/7/7 11:48
        */
       @RequiresPermissions("super:admin:list")
        @RequestMapping("list")
        public BaseResponse<?> superList(String keyWord, Integer state, String startTime, String endTime,
                                         @RequestParam(value = "pageNum", defaultValue = "0") Integer pageNum,
                                         @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize){
            keyWord = NullUtil.getStringNull(keyWord);
            state = NullUtil.getIntegerNull(state);
            startTime = NullUtil.getStringNull(startTime);
            endTime = NullUtil.getStringNull(endTime);
            return iSysAdminService.superList(keyWord, state, startTime, endTime, pageNum, pageSize);
        }
    这样我们的用户: admin 就可以访问 超级管理员列表 这个接口了





  • 相关阅读:
    join_tab计算代价
    outer join test
    突然觉得mysql优化器蛮简单
    将数据库字段从float修改为decimal
    小米初体验
    简述安装android开发环境
    Rust语言:安全地并发
    awk里的各种坑
    ubuntu下使用C语言开发一个cgi程序
    Ubuntu下安装和配置Apache2
  • 原文地址:https://www.cnblogs.com/ONFE/p/13447433.html
Copyright © 2011-2022 走看看