美文网首页程序员spring bootSpringBoot
Spring Boot 之 Shiro集成之路

Spring Boot 之 Shiro集成之路

作者: 糯米团子_大芒果 | 来源:发表于2019-02-01 22:12 被阅读8次

    最近想试试Shiro 和 JWT 集成,说实话,与传统的session机制相比,有优点也有缺点,这就需要你们自行斟酌使用啦,就说说遇到的坑而已。

    先说需求,密码加密储存,JWT。这就需要两种认证方式。

    别的不说先上pom.xml,都是基本的starter,用过spring boot 的都应该熟悉

    
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.2.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.manage</groupId>
        <artifactId>competition</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>competition</name>
        <description>Manage project for Competition</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- 阿里巴巴连接池Druid -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <!--<dependency>-->
                <!--<groupId>org.springframework.boot</groupId>-->
                <!--<artifactId>spring-boot-devtools</artifactId>-->
                <!--<scope>runtime</scope>-->
            <!--</dependency>-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
                <version>5.1.6</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <!--<scope>provided</scope>-->
            </dependency>
            <!--Junit-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!--cache-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-cache</artifactId>
            </dependency>
            <!--shiro-->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring-boot-web-starter</artifactId>
                <version>1.4.0</version>
            </dependency>
            <!--JWT-->
            <dependency>
                <groupId>com.auth0</groupId>
                <artifactId>java-jwt</artifactId>
                <version>3.7.0</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    自定义Realm

    两种验证方式,一种密码登录: 暂时没用到这种方式的权限认证也就没写逻辑了

    package com.manage.competition.shiro;
    
    import com.manage.competition.common.Const;
    import com.manage.competition.entity.Permission;
    import com.manage.competition.entity.Role;
    import com.manage.competition.entity.User;
    import com.manage.competition.repository.PermissionRepository;
    import com.manage.competition.repository.RoleRepository;
    import com.manage.competition.repository.UserRepository;
    import com.manage.competition.util.JwtUtil;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.crypto.hash.Sha256Hash;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.List;
    
    /**
     * Create with IDEA
     *
     * @Author:Vantcy
     * @Date: Create in 16:30 2019/1/25
     * @Description: 普通的自定义realm
     */
    
    public class AuthRealm extends AuthorizingRealm{
    
    
        @Autowired
        private UserRepository userRepository;
    
        /**
         * 此Realm只支持JwtToken
         * @return
         */
        @Override
        public Class<?> getAuthenticationTokenClass() {
            return UsernamePasswordToken.class;
        }
        @Override
        public boolean supports(AuthenticationToken token) {
            return token instanceof UsernamePasswordToken;
        }
    
        /**
         * 获取身份验证信息
         * Shiro中,最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
         *
         * @param authenticationToken 用户身份信息 token
         * @return 返回封装了用户信息的 AuthenticationInfo 实例
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("————————————————————————————auth身份认证方法————————————————————————————");
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            // 从数据库获取对应用户名密码的用户
            User user = userRepository.findByUsername(token.getUsername());
            if (user == null){
                throw new UnknownAccountException();
            }
            //是否激活
            if(user.getStatus().equals(Const.Status.DISABLE)){
                throw new DisabledAccountException();
            }
            //是否锁定
            if(user.getStatus().equals(Const.Status.ILLEGAL)) {
                throw new LockedAccountException();
            }
            if(user.getStatus().equals(Const.Status.ENABLE)){
                //盐值
                ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername());
                return new SimpleAuthenticationInfo(user, user.getPassword(),
                        credentialsSalt, getName());
            }
            return null;
        }
    
        /**
         * 获取授权信息
         *
         * @param principalCollection
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("————————————————————————————auth权限认证————————————————————————————");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            return info;
        }
    }
    
    

    一种token验证:这里有个坑就是一定要这个JwtRealm只支持认证JwtToken,不然会报错

    package com.manage.competition.shiro;
    
    import com.google.common.collect.Sets;
    import com.manage.competition.common.Const;
    import com.manage.competition.entity.Permission;
    import com.manage.competition.entity.Role;
    import com.manage.competition.entity.User;
    import com.manage.competition.repository.PermissionRepository;
    import com.manage.competition.repository.RoleRepository;
    import com.manage.competition.repository.UserRepository;
    import com.manage.competition.util.JwtUtil;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    
    /**
     * Create with IDEA
     *
     * @Author: gitee.com/KamisamaXX
     * @Date: Create in 15:38 2019/1/31
     * @Description: 基于JWT( JSON WEB TOKEN)的认证域
     */
    public class JwtRealm extends AuthorizingRealm {
    
        @Autowired
        private UserRepository userRepository;
    
        @Autowired
        private RoleRepository roleRepository;
    
        @Autowired
        private PermissionRepository permissionRepository;
    
        /**
         * 此Realm只支持JwtToken
         * @return
         */
        @Override
        public Class<?> getAuthenticationTokenClass() {
            return JwtToken.class;
        }
        @Override
        public boolean supports(AuthenticationToken token) {
            return token instanceof JwtToken;
        }
    
        /**
         * 认证
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("————————————————————————jwt身份认证方法————————————————————————");
            String token = (String) authenticationToken.getCredentials();
            String username = JwtUtil.getUsername(token);
            if (username == null || !JwtUtil.verify(token,username)) {
                throw new AuthenticationException("token认证失败!");
            }
            User user = userRepository.findByUsername(username);
            if (user == null) {
                throw new AuthenticationException("该用户不存在!");
            }
            if (user.getStatus() != Const.Status.ENABLE) {
                throw new AuthenticationException("该用户已被删除或封号!");
            }
            return new SimpleAuthenticationInfo(token, token, getName());
        }
    
        /**
         * 授权,JWT已包含访问主张只需要解析其中的主张定义就行了
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("————————————————————————————jwt权限认证————————————————————————————");
            String username = JwtUtil.getUsername(principalCollection.toString());
            User user = userRepository.findByUsername(username);
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //因为addRoles和addStringPermissions方法需要的参数类型是Collection
            //所以先创建两个collection集合
            Collection<String> rolesCollection = new HashSet<String>();
            Collection<String> permissionsCollection = new HashSet<String>();
            //获取user的Role的List集合
            List<Role> roles = roleRepository.findAllByUserId(user.getId());
            for (Role role:
                    roles) {
                //将每一个role的name装进collection集合
                rolesCollection.add(role.getRole());
                List<Permission> permissions = permissionRepository.findAllByRoleId(role.getId());
                for (Permission permission:
                        permissions) {
                    //将每一个permission的name装进collection集合
                    permissionsCollection.add(permission.getPerm());
                }
                //为用户授予权限
                info.addStringPermissions(permissionsCollection);
            }
            //为用户授予角色
            info.addRoles(rolesCollection);
            return info;
        }
    }
    
    

    Token也简单实现一下类,然后多加了一个字段而已,这个字段就是来储存token的

    package com.manage.competition.shiro;
    
    import lombok.Getter;
    import org.apache.shiro.authc.AuthenticationToken;
    
    
    /**
     * Create with IDEA
     *
     * @Author: gitee.com/KamisamaXX
     * @Date: Create in 10:52 2019/1/30
     * @Description: JWT令牌
     */
    @Getter
    public class JwtToken implements AuthenticationToken {
    
        private static final long serialVersionUID = 1984408664001215860L;
        /**
         * token
         */
        private String token;
    
        public JwtToken(String token) {
            this.token = token;
        }
    
        @Override
        public Object getPrincipal() {
            return token;
        }
    
        @Override
        public Object getCredentials() {
            return token;
        }
    }
    

    然后就是要自己定义一个Filter去拦截header里带有token字段的那些请求,然后去验证一下token是否有效。

    package com.manage.competition.shiro;
    
    
    import lombok.extern.slf4j.Slf4j;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.net.URLEncoder;
    
    /**
     * Create with IDEA
     *
     * @Author: gitee.com/KamisamaXX
     * @Date: Create in 10:45 2019/1/30
     * @Description: preHandle->isAccessAllowed->isLoginAttempt->executeLogin
     */
    @Slf4j
    public class JwtFilter extends BasicHttpAuthenticationFilter {
    
        /**
         * 如果带有 token,则对 token 进行检查,否则直接通过
         */
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue){
            //判断请求的请求头是否带上 "Token"
            if (isLoginAttempt(request, response)) {
                //如果存在,则进入 executeLogin 方法执行登入,检查 token 是否正确
                try {
                    executeLogin(request, response);
                    return true;
                } catch (Exception e) {
                    System.out.println(e);
                    //throw new UnsupportedTokenException("token 错误");
                }
            }
            //如果请求头不存在 Token,则可能是执行登陆操作或者是游客状态访问,无需检查 token,直接返回 true
            return true;
        }
    
        /**
         * 判断用户是否想要登入。
         * 检测 header 里面是否包含 Token 字段
         */
        @Override
        protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
            HttpServletRequest req = (HttpServletRequest) request;
            String token = req.getHeader("Token");
            return token != null;
        }
    
        /**
         * 执行登陆操作
         */
        @Override
        protected boolean executeLogin(ServletRequest request, ServletResponse response) throws AuthenticationException{
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            String token = httpServletRequest.getHeader("Token");
            // 提交给realm进行登入,如果错误他会抛出异常并被捕获
            JwtToken jwtToken = new JwtToken(token);
            // 如果没有抛出异常则代表登入成功,返回true
            SecurityUtils.getSubject().login(jwtToken);
            return true;
        }
    
        /**
         * 对跨域提供支持
         */
        @Override
        protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
            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);
        }
    
    }
    
    

    shiroConfig,在这里自定义一些shiro的配置项,需要定义一个hashedCredentialsMatcher去配置密码加密方式,注入两个Realm,securityManager里要设置取消session机制,注入filter规则等等都有相应的注释

    package com.manage.competition.shiro;
    
    import lombok.extern.slf4j.Slf4j;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.cache.MemoryConstrainedCacheManager;
    import org.apache.shiro.crypto.hash.Sha256Hash;
    import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
    import org.apache.shiro.mgt.DefaultSubjectDAO;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.mgt.SubjectDAO;
    import org.apache.shiro.realm.Realm;
    import org.apache.shiro.session.mgt.DefaultSessionManager;
    import org.apache.shiro.spring.LifecycleBeanPostProcessor;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.subject.SubjectContext;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.apache.shiro.web.mgt.DefaultWebSubjectFactory;
    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import javax.servlet.Filter;
    import java.util.*;
    
    /**
     * Create with IDEA
     *
     * @Author:Vantcy
     * @Date: Create in 15:54 2019/1/25
     * @Description:
     */
    @Configuration
    @Slf4j
    public class ShiroConfig {
    
        /**
         * 密码校验规则HashedCredentialsMatcher
         * 这个类是为了对密码进行编码的 ,
         * 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
         * 这个类也负责对form里输入的密码进行编码
         * 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
         */
        @Bean(name = "hashedCredentialsMatcher")
        public HashedCredentialsMatcher hashedCredentialsMatcher() {
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            //指定加密方式为MD5
            credentialsMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
            //加密次数
            credentialsMatcher.setHashIterations(1024);
            credentialsMatcher.setStoredCredentialsHexEncoded(true);
            log.info("hashedMatch注入成功");
            return credentialsMatcher;
        }
    
        /**
         * Sha256Hash 身份认证 realm;
         * <p>
         * 必须写这个类,并加上 @Bean 注解,目的是注入 Realm,
         * 否则会影响 Realm类 中其他类的依赖注入
         */
        @Bean(name = "authRealm")
        public AuthRealm authRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {
            AuthRealm authRealm = new AuthRealm();
            authRealm.setAuthenticationCachingEnabled(true);
            authRealm.setCredentialsMatcher(matcher);
            authRealm.setCachingEnabled(true);
            authRealm.setCacheManager(new MemoryConstrainedCacheManager());
            log.info("TwtRealm类注入成功");
            return authRealm;
        }
    
        /**
         * JWT Token身份认证 realm;
         * <p>
         * 必须写这个类,并加上 @Bean 注解,目的是注入 Realm,
         * 否则会影响 Realm类 中其他类的依赖注入
         */
        @Bean(name = "jwtRealm")
        public JwtRealm jwtRealm() {
            JwtRealm jwtRealm = new JwtRealm();
            jwtRealm.setAuthenticationCachingEnabled(true);
            jwtRealm.setCachingEnabled(true);
            jwtRealm.setCacheManager(new MemoryConstrainedCacheManager());
            log.info("TwtRealm类注入成功");
            return jwtRealm;
        }
    
        /**
         * 注入 securityManager
         */
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("jwtRealm") JwtRealm jwtRealm, @Qualifier("authRealm") AuthRealm authRealm) {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            StatelessSubjectFactory statelessSubjectFactory= new StatelessSubjectFactory();
    
            DefaultSessionManager defaultSessionManager = new DefaultSessionManager();
            defaultSessionManager.setSessionValidationSchedulerEnabled(false);
    
            DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
            defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
    
            DefaultSubjectDAO defaultSubjectDAO = new DefaultSubjectDAO();
            defaultSubjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
    
            Collection<Realm> realms = new HashSet<>();
            realms.add(jwtRealm);
            realms.add(authRealm);
            // 设置realm.
            securityManager.setRealms(realms);
            securityManager.setSubjectFactory(statelessSubjectFactory);
            securityManager.setSessionManager(defaultSessionManager);
            securityManager.setSubjectDAO(defaultSubjectDAO);
    
            log.info("SecurityManager类注入成功");
            return securityManager;
        }
    
        /**
         * 先走 filter ,然后 filter 如果检测到请求头存在 token,则用 token 去 login,走 Realm 去验证
         */
        @Bean(name = "shiroFilterFactoryBean")
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    
            // 添加自己的过滤器并且取名为jwt
            Map<String, Filter> filterMap = new HashMap<>();
            //设置我们自定义的JWT过滤器
            filterMap.put("jwt", new JwtFilter());
            shiroFilterFactoryBean.setFilters(filterMap);
    
    
            // 必须设置 SecurityManager
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            // setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
            shiroFilterFactoryBean.setLoginUrl("/login");
            // 设置无权限时跳转的 url;
            shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");
    
            // 设置拦截器
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
            //开放登陆接口
            filterChainDefinitionMap.put("/user/login", "anon");
            //开放注册接口
            filterChainDefinitionMap.put("/user/register", "anon");
            //其余接口一律拦截
            //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
            filterChainDefinitionMap.put("/**", "jwt");
    
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            log.info("Shiro拦截器工厂类注入成功");
            return shiroFilterFactoryBean;
        }
    
    
        @Bean
        public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
            /**
             * setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
             * 在@Controller注解的类的方法中加入@RequiresRole等shiro注解,会导致该方法无法映射请求,导致返回404。
             * 加入这项配置能解决这个bug
             */
            defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
            defaultAdvisorAutoProxyCreator.setUsePrefix(true);
            log.info("解决Shiro注解bug类注入成功");
            return defaultAdvisorAutoProxyCreator;
        }
    
        /**
         * 配置shiro跟spring的关联
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            log.info("Shiro关联spring类注入成功");
            return advisor;
        }
    
        /**
         * lifecycleBeanPostProcessor是负责生命周期的 , 初始化和销毁的类
         * (可选)
         */
        @Bean(name = "lifecycleBeanPostProcessor")
        public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
            log.info("lifecycleBeanPostProcessor生命周期类注入成功");
            return new LifecycleBeanPostProcessor();
        }
    }
    

    这里涉及到两个认证方式,authRealm 和 JwtRealm ,第一个是加入了hashMatch,为了和数据库里加密的密码比对,第二种为了验证token,而在shiro中,多realm匹配会有一个问题,

    像这种按默认方式去把两种realm都设置到securityManager里时,每次请求一来,就必须要这两个认证方式都通过了,才算验证成功,所以有两个办法,第一种像这篇文章写的那样去自定义ModularRealmAuthenticator,而在我这里,因为使用到的两种token不同,所以简单的限制了一个realm只能认证一种token,在上面的两个Realm代码里你可以看到 还有这样
    直接限定死了能认证的token类型,虽然说简单省事,但是扩展性低。

    最后,个人拙见,JWT有他自己的适用场景,session也有他自己的用处,如果是一个单一的WEB应用的话还是使用session机制叭

    相关文章

      网友评论

        本文标题:Spring Boot 之 Shiro集成之路

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