1. 程式人生 > 資料庫 >SpringBoot:Shiro 整合 Redis

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;    }}

小結

是不是很爽,以後重啟應用再也不用擔心使用者投訴了?