• Spring Boot + shiro 去除Redis缓存


    记录一些开发日常

    之前的项目shiro都是和Redis整合在一起的,直到甲方要求项目部署到国产服务器上,国产服务器不支持Redis怎么办,只能改喽。
    网上搜一下,修改方案千奇百怪,自己动手丰衣足食!

    第一步:修改ShiroConfig

    这一步就是把redis实现的缓存,改用session
    修改前:

    
    import lombok.Data;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.session.mgt.SessionManager;
    import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.crazycake.shiro.RedisCacheManager;
    import org.crazycake.shiro.RedisManager;
    import org.crazycake.shiro.RedisSessionDAO;
    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import javax.servlet.Filter;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    /**
     * @description:shiro配置
     */
    @Configuration
    @Data
    public class ShiroConfig {
    
        @Value("${spring.redis.host}")
        private String host;
    
        @Value("${spring.redis.port}")
        private int port;
    
        @Value("${spring.redis.password:}")
        private String password;
    
        @Value("${shiro.timeout}")
        private int timeout;
    
        /**
         * Filter工厂,设置对应的过滤条件和跳转条件
         * @return ShiroFilterFactoryBean
         */
        @Bean
        public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
    
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
    
            Map<String, Filter> filters = new HashMap<>();
    
            filters.put("authc",new MyShiroAuthFilter());
            shiroFilterFactoryBean.setFilters(filters);
    
            // 过滤器链定义映射
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
    
            /*
             * anon:可以匿名访问的url,
             * authc:认证通过才可以访问的url;
             * 过滤链定义,从上向下顺序执行,authc 应放在 anon 下面
             * */
            filterChainDefinitionMap.put("/login/login", "anon");
            filterChainDefinitionMap.put("/queryController/downloadZip", "anon");
            // 配置不会被拦截的链接 顺序判断
            filterChainDefinitionMap.put("/css/**", "anon");
            filterChainDefinitionMap.put("/fonts/**", "anon");
            filterChainDefinitionMap.put("/img/**", "anon");
            filterChainDefinitionMap.put("/js/**", "anon");
            filterChainDefinitionMap.put("/html/**", "anon");
            filterChainDefinitionMap.put("/file/**", "anon");
    
            filterChainDefinitionMap.put("/images/**", "anon");
    
            /*****************************swagger***************************/
            filterChainDefinitionMap.put("/swagger-ui.html", "anon");
            filterChainDefinitionMap.put("/webjars/**", "anon");
            filterChainDefinitionMap.put("/v2/**", "anon");
            filterChainDefinitionMap.put("/swagger-resources/**", "anon");
            /***************************************************************/
    
            // 认证通过才可以访问的url
            filterChainDefinitionMap.put("/**", "authc");
    
            //前后端分离中登录累面跳转应由前端路由控制,后台仅返回json数据, 对应LoginController中unauth请求,
            // 未登录已经在MyShiroAuthFilter的onAccessDenied进行拦截,为了防止拦截失效所以在这再做一次判断,通常不会执行这步代码。
            shiroFilterFactoryBean.setLoginUrl("/login/un_auth");
    
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
    
        /**
         * 凭证匹配器(由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了)
         * @return HashedCredentialsMatcher
         */
        @Bean
        public HashedCredentialsMatcher hashedCredentialsMatcher() {
            HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
            // 散列算法:这里使用MD5算法;
            hashedCredentialsMatcher.setHashAlgorithmName("md5");
            // 散列的次数,比如散列两次,相当于 md5(md5(""));
            hashedCredentialsMatcher.setHashIterations(PassWordInitConfig.MD5_COUNT);
            return hashedCredentialsMatcher;
        }
    
        /**
         * 将自己的验证方式加入容器
         * @return MyShiroRealm
         */
        @Bean
        public MyShiroRealm myShiroRealm() {
            MyShiroRealm myShiroRealm = new MyShiroRealm();
            myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
            return myShiroRealm;
        }
    
        /**
         * RedisSessionDAO shiro sessionDao层的实现 通过redis, 使用的是shiro-redis开源插件
         * @return RedisSessionDAO
         */
        @Bean
        public RedisSessionDAO redisSessionDAO() {
            RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
            redisSessionDAO.setRedisManager(redisManager());
            redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());
            redisSessionDAO.setExpire(timeout*60);
            return redisSessionDAO;
        }
    
        /**
         * Session ID 生成器
         * @return JavaUuidSessionIdGenerator
         */
        @Bean
        public JavaUuidSessionIdGenerator sessionIdGenerator() {
            return new JavaUuidSessionIdGenerator();
        }
    
        /**
         * 自定义sessionManager
         * @return SessionManager
         */
        @Bean
        public SessionManager sessionManager() {
            MySessionManager mySessionManager = new MySessionManager();
            mySessionManager.setSessionDAO(redisSessionDAO());
            return mySessionManager;
        }
    
        /**
         * 配置shiro redisManager, 使用的是shiro-redis开源插件
         * @return RedisManager
         */
        private RedisManager redisManager() {
            RedisManager redisManager = new RedisManager();
            redisManager.setHost(host+":"+port);
            if (StringUtils.isNotBlank(password)) {
                redisManager.setPassword(password);
            }
            return redisManager;
        }
    
        /**
         * cacheManager 缓存 redis实现, 使用的是shiro-redis开源插件
         * @return RedisCacheManager
         */
        @Bean
        public RedisCacheManager cacheManager() {
            RedisCacheManager redisCacheManager = new RedisCacheManager();
            redisCacheManager.setRedisManager(redisManager());
            // 必须要设置主键名称,shiro-redis 插件用过这个缓存用户信息
            redisCacheManager.setPrincipalIdFieldName("userAccount");
            return redisCacheManager;
        }
    
        /**
         * description: 权限管理,配置主要是Realm的管理认证
         * @return SecurityManager
         */
        @Bean
        public SecurityManager securityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(myShiroRealm());
            // 自定义session管理 使用redis
            securityManager.setSessionManager(sessionManager());
            // 自定义缓存实现 使用redis
            securityManager.setCacheManager(cacheManager());
            return securityManager;
        }
    
        /**
         * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
         * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
         */
        @Bean
        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            advisorAutoProxyCreator.setProxyTargetClass(true);
            return advisorAutoProxyCreator;
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215

    修改后:

    
    import lombok.Data;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.cache.ehcache.EhCacheManager;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.session.mgt.SessionManager;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import javax.servlet.Filter;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    /**
     * @description:shiro配置
     */
    @Configuration
    @Data
    public class ShiroConfig {
    
        /**
         * Filter工厂,设置对应的过滤条件和跳转条件
         * @return ShiroFilterFactoryBean
         */
        @Bean
        public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
    
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
    
            Map<String, Filter> filters = new HashMap<>();
    
            filters.put("authc",new MyShiroAuthFilter());
            shiroFilterFactoryBean.setFilters(filters);
    
            // 过滤器链定义映射
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
    
            /*
             * anon:可以匿名访问的url,
             * authc:认证通过才可以访问的url;
             * 过滤链定义,从上向下顺序执行,authc 应放在 anon 下面
             * */
            filterChainDefinitionMap.put("/login/login", "anon");
            filterChainDefinitionMap.put("/queryController/downloadZip", "anon");
            // 配置不会被拦截的链接 顺序判断
            filterChainDefinitionMap.put("/css/**", "anon");
            filterChainDefinitionMap.put("/fonts/**", "anon");
            filterChainDefinitionMap.put("/img/**", "anon");
            filterChainDefinitionMap.put("/js/**", "anon");
            filterChainDefinitionMap.put("/html/**", "anon");
            filterChainDefinitionMap.put("/file/**", "anon");
    
            filterChainDefinitionMap.put("/images/**", "anon");
    
            /*****************************swagger***************************/
            filterChainDefinitionMap.put("/swagger-ui.html", "anon");
            filterChainDefinitionMap.put("/webjars/**", "anon");
            filterChainDefinitionMap.put("/v2/**", "anon");
            filterChainDefinitionMap.put("/swagger-resources/**", "anon");
            /***************************************************************/
    
            // 认证通过才可以访问的url
            filterChainDefinitionMap.put("/**", "authc");
    
            //前后端分离中登录累面跳转应由前端路由控制,后台仅返回json数据, 对应LoginController中unauth请求,
            // 未登录已经在MyShiroAuthFilter的onAccessDenied进行拦截,为了防止拦截失效所以在这再做一次判断,通常不会执行这步代码。
            shiroFilterFactoryBean.setLoginUrl("/login/un_auth");
    
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
    
        /**
         * 凭证匹配器(由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了)
         * @return HashedCredentialsMatcher
         */
        @Bean
        public HashedCredentialsMatcher hashedCredentialsMatcher() {
            HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
            // 散列算法:这里使用MD5算法;
            hashedCredentialsMatcher.setHashAlgorithmName("md5");
            // 散列的次数,比如散列两次,相当于 md5(md5(""));
            hashedCredentialsMatcher.setHashIterations(PassWordInitConfig.MD5_COUNT);
            return hashedCredentialsMatcher;
        }
    
        /**
         * 将自己的验证方式加入容器
         * @return MyShiroRealm
         */
        @Bean
        public MyShiroRealm myShiroRealm() {
            MyShiroRealm myShiroRealm = new MyShiroRealm();
            myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
            return myShiroRealm;
        }
    
        @Bean
        public DefaultSecurityManager securityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            // 设置realm.
            securityManager.setRealm(myShiroRealm());
            //设置缓存
            securityManager.setCacheManager(getCacheManager());
            securityManager.setSessionManager(sessionManager());
    
            return securityManager;
        }
    
        /**
         *
         * 缓存框架
         * @return
         */
        @Bean
        public EhCacheManager getCacheManager(){
            EhCacheManager ehCacheManager = new EhCacheManager();
            ehCacheManager.setCacheManagerConfigFile("classpath:shiro-ehcache.xml");
            return ehCacheManager;
        }
    
        /**
         * 自定义sessionManager
         * @return SessionManager
         */
        @Bean
        public SessionManager sessionManager() {
            MySessionManager mySessionManager = new MySessionManager();
            return mySessionManager;
        }
    
    
        /**
         * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
         * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
         */
        @Bean
        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            advisorAutoProxyCreator.setProxyTargetClass(true);
            return advisorAutoProxyCreator;
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160

    第二步:新增shiro-ehcache.xml

    在上一步可以看到,增加了一个EhCacheManager 的缓存框架,里面有一个配置文件classpath:shiro-ehcache.xml,这文件创建在哪呢,没错就是resource

    
    <ehcache>
        <defaultCache
                maxElementsInMemory="1000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                memoryStoreEvictionPolicy="LRU">
        defaultCache>
    ehcache>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    第三步:注释pom引入的Redis依赖

    这一步就不用多说了,搜索redis关键字注释依赖,然后clean一下,启动项目看看是否正常

  • 相关阅读:
    后端程序员对于 Docker 要掌握多少才行?我的答案是
    十四天学会C++之第五天:类的详细讨论
    RabbitMQ基础
    使用 gst-plugins-bad 里面的 gst-element-maker 工具创建gstreamer 插件
    API设计笔记:pimpl技巧
    【算法训练-动态规划 一】【应用DP问题】零钱兑换、爬楼梯、买卖股票的最佳时机I、打家劫舍
    ElementUI首页导航和左侧菜单静态页面的实现,以及Mockjs和总线的介绍
    unity 判断平台
    哔哩哔哩面试经验分享
    MViTv2:Facebook出品,进一步优化的多尺度ViT | CVPR 2022
  • 原文地址:https://blog.csdn.net/qq_25391785/article/details/127430213