前段時間作了一個圖牀的小項目,安全框架使用的是Shiro
。爲了使用戶7x24
小時訪問,決定把項目由單機升級爲集羣部署架構。可是安全框架shiro
只有單機存儲的SessionDao
,儘管Shrio
有基於Ehcache-rmi
的組播/廣播實現,然而集羣的分佈每每是跨網段的,甚至是跨地域的,因此尋求新的方案。html
使用 redis
集中存儲,實現分佈式集羣共享用戶信息,這裏咱們採用第三方開源插件crazycake
來實現,pom.xml
引入:redis
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis</artifactId> <version>3.2.3</version> </dependency>
配置 application.properties
:spring
# Redis # 數據庫索引(默認爲0) redis.database=0 # 服務器地址 變動爲本身的 redis.host=127.0.0.1 # 服務器鏈接端口 redis.port=6379 # 服務器鏈接密碼,若是不設置密碼註釋掉便可 # redis.password= # 鏈接超時時間(毫秒) redis.timeout=30000
原本crazycake
插件已經實現了RedisManager
,可是參數不可配,這裏咱們須要本身重寫一下:數據庫
/** * 重寫 RedisManager * 博客:https://blog.52itstyle.vip */ 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
:緩存
@Data @ConfigurationProperties(prefix = "redis") public class RedisProperties { private String host; private int port; private int timeout; private String password; private int database; }
配置 ShiroConfig
:安全
/** * Shiro權限配置 * 必定要配置 @Configuration 和 @EnableConfigurationProperties 註解 * 博客:https://blog.52itstyle.vip */ @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; } }
是否是很爽,之後重啓應用不再用擔憂用戶投訴了?服務器
最後,推薦下小黃圖:https://www.cloudbed.vipsession