分布式下session认证存在的问题
session认证: 客户端在服务端登录认证后,服务端自己保存用户信息,并把session_id放到客户端的cookie中,下次客户端带着cookie访问服务端就可以直接访问
这种session认证在分布式下会存在问题
-
无法访问其他相同模块的集群服务器
因为只在一个服务端上保存信息,其他相同的集群服务器没保存
-
无法访问其他模块的服务器
因为其他模块的服务器上未保存信息,所以无法访问
解决方案
-
session复制
- 只需要改tomcat配置文件
- 占服务器的带宽,内存,浪费资源
-
客户端存储session
- 服务端不用存session
- 不安全(被篡改),cookie容量有限
-
hash一致性(浏览器从哪个IP访问了服务端,就一直用那个服务端处理该浏览器的请求)
- nginx提供了根据IP绑定服务端的负载均衡算法,只改nginx配置文件即可
- 无法解决问题2
-
使用中间件Redis统一存储session
- 问题2访问其他模块服务端时,可以使用子域session共享解决
- 多增加了网络调用,redis获取数据比内存慢
-
使用基于token的认证方式
使用Spring session
解决分布式下session认证问题
spring session可以采用中间件redis统一存储session方案解决这个问题,同时还解决了redis获取数据速度慢的问题
-
导入依赖
<!-- spring session2--> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
-
编写配置文件
#配置存到redis spring.session.store-type=redis #过期时间 server.servlet.session.timeout=30m
-
添加注解开启功能
@EnableRedisHttpSession
此时已经完成了将session存在redis中的功能,还未解决session子域问题
解决session子域问题,实际上就是修改产生session时设置的Domain
配置解决session域问题和序列化问题
@Configuration
public class GulimallSessionConfig {
/**
* 解决session域问题
*
* @return
*/
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
//设置Domain
cookieSerializer.setDomainName("gulimall.com");
//设置session名
cookieSerializer.setCookieName("GULISESSION");
return cookieSerializer;
}
/**
* 设置session存储redis序列化为json格式
*
* @return
*/
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}
Spring session原理
- @EnableRedisHttpSession导入@Import(RedisHttpSessionConfiguration.class)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-of1NcEsI-1626313635270)(项目整合认证服务.assets/
)]
-
RedisHttpSessionConfiguration中向容器添加了SessionRepository的实现类RedisOperationsSessionRepository
2.1 SessionRepository接口的方法提供了对session的增删改查操作,那它的实现类RedisOperationsSessionRepository可想而知就是redis对session的增删改查操作
-
RedisHttpSessionConfiguration继承了父类SpringHttpSessionConfiguration
3.1 SpringHttpSessionConfiguration的init中实现了之前我们加入容器的CookieSerializer(有就用我们的,没有就用默认的)
3.2 SpringHttpSessionConfiguration还向容器中添加了SessionRepositoryFilter,SessionRepositoryFilter最终实现Filter接口,每个请求必须经过filter
3.3 SessionRepositoryFilter构造的时候,会将SessionRepository放进去(这里会放实现类RedisOperationsSessionRepository)
3.4 SessionRepositoryFilter使用装饰模式,在doFilterInternal方法中将原生请求,响应封装为SessionRepositoryRequestWrapper,SessionRepositoryResponseWrapper
3.5 SessionRepositoryRequestWrapper中重写了getSession,所以我们拿到session存东西,一定会经过请求链,被它们用redis根据情况执行增删改查操作 [获取session要使用原生请求获得(HttpSession session1 = request.getSession(); HttpServletRequest request)]
总结
-
@EnableRedisHttpSession导入@Import(RedisHttpSessionConfiguration.class)
-
RedisHttpSessionConfiguration中向容器添加了SessionRepository的实现类RedisOperationsSessionRepository
- SessionRepository接口的方法提供了对session的增删改查操作,那它的实现类RedisOperationsSessionRepository可想而知就是redis对session的增删改查操作
-
RedisHttpSessionConfiguration继承了父类SpringHttpSessionConfiguration
-
SpringHttpSessionConfiguration的init中实现了之前我们加入容器的CookieSerializer(有就用我们的,没有就用默认的)
-
SpringHttpSessionConfiguration还向容器中添加了SessionRepositoryFilter,SessionRepositoryFilter最终实现Filter接口,每个请求必须经过filter
-
SessionRepositoryFilter构造的时候,会将SessionRepository放进去(这里会放实现类RedisOperationsSessionRepository)
-
SessionRepositoryFilter使用装饰模式,在doFilterInternal方法中将原生请求,响应封装为SessionRepositoryRequestWrapper,SessionRepositoryResponseWrapper
-
SessionRepositoryRequestWrapper中重写了getSession,所以我们拿到session存东西,一定会经过请求链,被它们用redis根据情况执行增删改查操作[获取session要使用原生请求获得(HttpSession session1 = request.getSession(); HttpServletRequest request)]
-
-
核心组件
-
SessionRepository(实现类RedisOperationsSessionRepository)
- 使用redis对session进行增删改查
-
SessionRepositoryFilter
- 装饰模式封装请求,响应,重写getSession的实现,用SessionRepository来对session进行增删改查
-