前言html
前段時間作了一個圖牀的小項目,安全框架使用的是Shiro。爲了使用戶7x24小時訪問,決定把項目由單機升級爲集羣部署架構。可是安全框架shiro只有單機存儲的SessionDao,儘管Shrio有基於Ehcache-rmi的組播/廣播實現,然而集羣的分佈每每是跨網段的,甚至是跨地域的,因此尋求新的方案。
架構
方案java
使用 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;
}}
|
小結redis
是否是很爽,之後重啓應用不再用擔憂用戶投訴了?
更多技術資訊可關注:itheimaGZ公冢號獲取