分布式RedisSession的探索
分布式RedisSession的探索
为什么需要分布式session,对于API接口是不需要session的,对于后台管理页面,基于session的认证及授权如shiro是需要分布式session的。
spring cloud常用的分布式session解决方案redisSession是基于cookie来存贮session的,对于前后端分离的项目,可以在请求中携带cookie。
1. 搭建一个项目 distribute-session
启动类入口增加 @EnableRedisHttpSession注解 启用分布式session,将服务注册到注册中心nacos.
主要依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
增加redis配置
spring:
redis:
host: 127.0.0.1
port: 6379
# password: 123456
增加测试方法,通过指定不同port启动两个服务。
@GetMapping("/index")
public String index(HttpServletRequest request){
String sessionId = request.getSession().getId();
log.info("HomeController index port {} sessionId: {}",port,sessionId);
return sessionId;
}
2. 创建网关项目
路由配置
spring:
cloud:
gateway:
#路由配置:参数为一个List
routes:
#唯一标识
- id: paw-distribute-session-route
#转发的地址,写服务名称
uri: lb://paw-distribute-session
#判断匹配条件,即地址带有path的请求
predicates:
- Path=/distribute-session-api/**
filters:
#去掉Path前缀,参数为1代表去掉1ceng
- StripPrefix=1
启动服务,访问 http://127.0.0.1:9000/distribute-session-api/index 会发现 不同port服务返回的sessionId相同,即分布式session搭建完成。
3. RedisHttpSession的探索
从注解中看到配置类 RedisHttpSessionConfiguration,类中注入了session持久化的类RedisIndexedSessionRepository,该类实现了SessionRepository。
查看createSession方法,通过MapSession以UUID的方式创建了sessionId,通过redisTemplate存储到redis中
public RedisSession createSession() {
MapSession cached = new MapSession();
if (this.defaultMaxInactiveInterval != null) {
cached.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
}
RedisSession session = new RedisSession(cached, true);
session.flushImmediateIfNecessary();
return session;
}
private static String generateId() {
return UUID.randomUUID().toString();
}
EnableRedisHttpSession 说明中更多的配置参见 EnableSpringHttpSession,打开配置类SpringHttpSessionConfiguration,其中有一些 required=false的配置,程序内部提供了默认实现,即用户可以进行进行自定义配置。如HttpSessionIdResolver 提供了基于cookie的sessionId解析器,并默认进行base64编码。
private HttpSessionIdResolver httpSessionIdResolver = this.defaultHttpSessionIdResolver;
@Autowired(required = false)
public void setHttpSessionIdResolver(HttpSessionIdResolver httpSessionIdResolver) {
this.httpSessionIdResolver = httpSessionIdResolver;
}
支持redisHttpSession的大致配置及流程已有脉路。
4. 基于token的分布式session
思考: 对于前后端分离的管理后台项目,是否可以携带token的方式进行保持session会话。
自定义 HttpSessionIdResolver 并注入到配置中
// 实现接口 HttpSessionIdResolver
public class TokenHttpSessionIdResolver implements HttpSessionIdResolver {
public static final String TOKEN = "token";
public TokenHttpSessionIdResolver(){
}
@Override
public List<String> resolveSessionIds (HttpServletRequest request) {
List<String> list = new ArrayList<>();
// 从header中取出token作为sessionId
String token = request.getHeader(TOKEN);
if(StrUtil.isNotEmpty(token)){
list.add(token);
}
return list;
}
@Override
public void setSessionId (HttpServletRequest request, HttpServletResponse response, String sessionId) {
}
@Override
public void expireSession (HttpServletRequest request, HttpServletResponse response) {
}
}
@Configuration
public class WebConfiguration {
// 注入bean
@Bean
public HttpSessionIdResolver httpSessionIdResolver(){
return new TokenHttpSessionIdResolver();
}
}
增加获取token的接口
@GetMapping("/getToken")
public String getToken(HttpServletRequest request){
String sessionId = request.getSession().getId();
log.info("sessionId: {}",sessionId);
return sessionId;
}
获取token后,再次请求在header中携带token,sessionId保持不变。
此种方式仅供娱乐研究。
总结:
RedisHttpSession 通过生成一个UUID的session 存储在Redis中,并写入到cookies中返回给浏览器,浏览器再次访问时携带cookies, springHttpSession解析获取session,并根据redis存贮的对比一致,则是同一个会话。
- 点赞
- 收藏
- 关注作者
评论(0)