欢迎关注专栏:Java架构技术进阶。里面有大量batj面试题集锦,还有各种技术分享,如有好文章也欢迎投稿哦。
前言
前段时间做了一个图床的小项目,安全框架使用的是Shiro
。为了使用户7x24
小时访问,决定把项目由单机升级为集群部署架构。但是安全框架shiro
只有单机存储的SessionDao
,尽管Shrio
有基于Ehcache-rmi
的组播/广播实现,然而集群的分布往往是跨网段的,甚至是跨地域的,所以寻求新的方案。
架构
方案
使用 redis
集中存储,实现分布式集群共享用户信息,这里我们采用第三方开源插件crazycake
来实现,pom.xml
引入:
<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
:
# Redis
# 数据库索引(默认为0)
redis.database=0
# 服务器地址 变更为自己的
redis.host=127.0.0.1
# 服务器连接端口
redis.port=6379
# 服务器连接密码,如果不设置密码注释掉即可
# redis.password=
# 连接超时时间(毫秒)
redis.timeout=30000
本来crazycake
插件已经实现了RedisManager
,但是参数不可配,这里我们需要自己重写一下:
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 注解
*/
@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;
}
}
小结
最后我们该如何学习?
1、看视频进行系统学习
这几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。
另外,我自己也珍藏了好几套视频资料躺在网盘里,有需要的我也可以分享给你:
2、读源码,看实战笔记,学习大神思路
“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。
Spring源码深度解析:
Mybatis 3源码深度解析:
Redis学习笔记:
Spring Boot核心技术-笔记:
3、面试前夕,刷题冲刺
面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。
关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:
只有技术过硬,在哪儿都不愁就业,“万般带不去,唯有业随身”学习本来就不是在课堂那几年说了算,而是在人生的旅途中不间断的事情。
人生短暂,别稀里糊涂的活一辈子,不要将就。
资料领取方式:点击蓝色传送门免费领取上述资料
文章内容中涉及到的Java面试题、源码文档,技术笔记等学习资料,均可以免费分享给大家学习,只需你动动手多多支持即可!
94061)]
只有技术过硬,在哪儿都不愁就业,“万般带不去,唯有业随身”学习本来就不是在课堂那几年说了算,而是在人生的旅途中不间断的事情。
人生短暂,别稀里糊涂的活一辈子,不要将就。
资料领取方式:点击蓝色传送门免费领取上述资料