SpringBoot:Shiro 整合 Redis,重啟應用也不用擔心用戶投訴啦

以下文章來源於“小柒2012”的個人博客:https://blog.52itstyle.vip/archives/5092/

前言

前段時間做了一個圖床的小項目,安全框架使用的是Shiro。為了使用戶7x24小時訪問,決定把項目由單機升級為集群部署架構。但是安全框架shiro只有單機存儲的SessionDao,儘管Shrio有基於Ehcache-rmi的組播/廣播實現,然而集群的分佈往往是跨網段的,甚至是跨地域的,所以尋求新的方案。

架構

SpringBoot:Shiro 整合 Redis,重啟應用也不用擔心用戶投訴啦

方案

使用 redis 集中存儲,實現分佈式集群共享用戶信息,這裡我們採用第三方開源插件crazycake來實現,pom.xml 引入:

<code><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>/<code>

配置 application.properties:

<code># Redis
# 數據庫索引(默認為0)
redis.database=0
# 服務器地址 變更為自己的
redis.host=127.0.0.1
# 服務器連接端口
redis.port=6379
# 服務器連接密碼,如果不設置密碼註釋掉即可
# redis.password=
# 連接超時時間(毫秒)
redis.timeout=30000/<code>

本來crazycake插件已經實現了RedisManager,但是參數不可配,這裡我們需要自己重寫一下:

<code>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();
}
}/<code>

參數配置 RedisProperties:

<code>@Data
@ConfigurationProperties(prefix = "redis")
public class RedisProperties {

private String host;
private int port;
private int timeout;
private String password;
private int database;
}/<code>

配置 ShiroConfig:

<code>/**
* 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> 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;
}
}/<string>/<code>

小結

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

關注我,後續更多幹貨奉上!


分享到:


相關文章: