SpringBoot:Shiro 整合 Redis

前言

前段时间做了一个图床的小项目,安全框架使用的是Shiro。为了使用户7x24小时访问,决定把项目由单机升级为集群部署架构。但是安全框架shiro只有单机存储的SessionDao,尽管Shrio有基于Ehcache-rmi的组播/广播实现,然而集群的分布往往是跨网段的,甚至是跨地域的,所以寻求新的方案。

架构

方案

使用 redis 集中存储,实现分布式集群共享用户信息,这里我们采用第三方开源插件crazycake来实现,pom.xml 引入:
[XML] 纯文本查看 复制代码
?
<dependency>    [/align][align=left]<groupId>org.springframework.boot</groupId>  [/align][align=left]  <artifactId>spring-boot-starter-data-redis</artifactId>[/align][align=left]</dependency>[/align][align=left]<dependency>   [/align][align=left] <groupId>org.crazycake</groupId>  [/align][align=left]  <artifactId>shiro-redis</artifactId> [/align][align=left]   <version>3.2.3</version>[/align][align=left]</dependecy>
配置 application.properties:
[PowerShell] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
8
9
# Redis# 数据库索引(默认为0)redis.database=0
# 服务器地址 变更为自己的
redis.host=127.0.0.1
# 服务器连接端口
redis.port=6379
# 服务器连接密码,如果不设置密码注释掉即可
# redis.password=
# 连接超时时间(毫秒)
redis.timeout=30000
本来crazycake插件已经实现了RedisManager,但是参数不可配,这里我们需要自己重写一下:
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public class RedisManager extends WorkAloneRedisManager implements IRedisManager {   
private RedisProperties redis;  
 private JedisPool jedisPool;  
 public RedisManager(RedisProperties redis) {      
 this.redis = redis;    }   
private void init() {      
 synchronized(this) {         
  if (this.jedisPool == null) {               
this.jedisPool = new JedisPool(this.getJedisPoolConfig(), redis.getHost(), redis.getPort(),                       
redis.getTimeout(), redis.getPassword(), redis.getDatabase());           
}       
}   
}   
@Override  
 protected Jedis getJedis() {       
if (this.jedisPool == null) {          
 this.init();       
}       
return this.jedisPool.getResource();   
}}
参数配置 RedisProperties:
[Java] 纯文本查看 复制代码
?
@Data
@ConfigurationProperties(prefix = "redis")
public class RedisProperties {   
private String host;   
private int port;   
private int timeout;   
private String password;   
private int database;}
配置 ShiroConfig:
[Java] 纯文本查看 复制代码
?
/** * Shiro权限配置 * 一定要配置 @Configuration 和 @EnableConfigurationProperties 注解 */
@Configuration
@EnableConfigurationProperties({RedisProperties.class})
public class ShiroConfig {   
private RedisProperties redis;   
public ShiroConfig(RedisProperties redis) {       
this.redis = redis;   
}   
@Bean  
 public UserRealm userRealm() {       
return new UserRealm();   
}   
@Bean   
public ShiroFilterFactoryBean shiroFilterFactoryBean (SecurityManager securityManager) {
       ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/index.html");
       shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        // 拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
       /**
         * 静态文件
         */
       filterChainDefinitionMap.put("/file/**","anon");
        /**
         * 登录注册
         */
       filterChainDefinitionMap.put("/register.shtml","anon");
       filterChainDefinitionMap.put("/login.shtml","anon");
        /**
        * 管理后台
        */
       filterChainDefinitionMap.put("/sys/**", "roles[admin]");
       filterChainDefinitionMap.put("/**", "authc");
       shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
       return shiroFilterFactoryBean;
   }
    @Bean
    public SessionsSecurityManager securityManager() {
       DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
       securityManager.setCacheManager(cacheManager());
        securityManager.setSessionManager(sessionManager());
       return securityManager;
   }
   @Bean
    public DefaultWebSessionManager sessionManager() {
       DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
       sessionManager.setSessionIdUrlRewritingEnabled(false);
        sessionManager.setSessionDAO(redisSessionDAO());
       return sessionManager;
   }
    @Bean
   public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }
   /**
     * cacheManager 缓存 redis实现
     * @return
     */
    public RedisCacheManager cacheManager() {
       RedisCacheManager redisCacheManager = new RedisCacheManager();
       redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
   }
    /**
    * 配置shiro redisManager
     * @return
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager(redis);
       return redisManager;
   }
    /**
    * RedisSessionDAO shiro sessionDao层的实现
    * 原理就是重写 AbstractSessionDAO
     * 有兴趣的小伙伴自行阅读源码
     */
   @Bean
    public RedisSessionDAO redisSessionDAO() {
       RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
       redisSessionDAO.setRedisManager(redisManager());
       return redisSessionDAO;
   }}

小结

是不是很爽,以后重启应用再也不用担心用户投诉了?
发布了551 篇原创文章 · 获赞 1 · 访问量 9003

猜你喜欢

转载自blog.csdn.net/xiaoyaGrace/article/details/104183575