前言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公冢号获取