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分布式存储
缓存
使用缓存存储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;
}