SpringBoot 分布式session
在如今服务器集群的情况下,用户登录会话状态的保存也从单机的变成了分布式要求的,下面详细说一下几种分布式session存储方案。
- session复制:在支持session复制的服务器上进行,同步session,保持session一致
方案:
tomcat-redis-session-manager
- session粘滞:强行分发session到各个服务器
方案:负载均衡
- cookie存储session:把sessionid存储到cookie中(不安全,cookie容易被盗取,可以存储不重要的数据)
- session集中管理:把用户的session存储在单台或者集群服务器的缓存中,所有web服务器从中拿取session,实现session共享
方案:Redis存储用户生成的sessionId或者存储保存sessionId的cookie
这里只讲解第四种方案,使用最多最稳定
Redis做缓存持久化存储session
Redis存储cookie,里面保存用户生成的uuid(token作为sessionId)
- cookie名称和过期时间
public static final String COOKIE_NAME_TOKEN = "token";
private static final ex = 3600;
- 创建cookie并存储到redis
private String addCookie(HttpServletResponse response,SeckillUser user){
String token = UUIDUtil.uuid();
redisService.set(token,user);//使用redis把token作为键存储user作为值 我使用jedis自己实现的也可以使用redisTemplate
Cookie cookie = new Cookie(COOKIE_NAME_TOKEN, token);//设置cookie 名称为token
cookie.setMaxAge(ex);//设置过期时间
cookie.setPath("/");
response.addCookie(cookie);
return token;
}
- uuid作为sessionid生成工具
public class UUIDUtil {
public static String uuid(){
return UUID.randomUUID().toString();
}
}
使用Shiro集成的crazy-cake
(使用Redis存储SessionId)
- shiro是一个Web安全框架,用于登录认证,用户身份授权,使用易于
spring-security
,还可以继承session、cookie分布式存储
不了解的可以看这篇博文:Shiro的使用以及集成redis做缓存
缓存
- 使用缓存存储session(单服务器使用EhCacheManager)
- 但是在分布式系统中,服务器集群情况下,EhCacheManager无法解决数据共享(会多次查询数据库),则选择使用redis作为缓存
Redis实现shiro缓存
- 分布式共享session和授权信息需要把session和授权持久化到数据库或者缓存 shiro集群为了防止多次插查询数据库
-
自定义实现类:或者使用crazycake开源shiro-redis实现好的工具
- RedisSessionDAO 可以继承EnterpriseCacheSessionDAO实现session控制
- RedisCache 继承Cache类实现具体redis操作缓存(remove、get、set、keys
- RedisCacheManager 实现接口CacheManager的getCache获得RedisCache交给securityManager管理
使用了ConcurrentMap管理数据和缓存,更加高效
- 在
ShiroConfig
配置类中把sessionManager
交给DefaultWebSecurityManager
管理
@Bean
public DefaultWebSessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//session时间
sessionManager.setGlobalSessionTimeout(redisConfig().getTimeout());
//删除无效session
sessionManager.setDeleteInvalidSessions(true);
log.info("sessionManager注入成功");
sessionManager.setSessionIdCookie(cookie());
// sessionDao 分布式共享session和授权信息需要把session和授权持久化到数据库或者缓存 shiro集群为了防止多次插查询数据库
sessionManager.setSessionDAO(redisSessionDao());
return sessionManager;
}
- 在
sessionManager
中注入cookie存储jsessionId
@Bean
public SimpleCookie cookie() {
SimpleCookie cookie = new SimpleCookie("JSESSIONID");
cookie.setHttpOnly(true);
cookie.setPath("/");
return cookie;
}
- 再在
sessionManager
中注入redisSessionDao
负责session持久化
@Bean
public RedisSessionDAO redisSessionDao(){
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());
return redisSessionDAO;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。