写点什么

分布式 session 之 RedisSession 的探索

作者:Rubble
  • 2022 年 4 月 10 日
  • 本文字数:2173 字

    阅读完需:约 7 分钟

为什么需要分布式 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 并注入到配置中


// 实现接口 HttpSessionIdResolverpublic 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) { }}
复制代码


@Configurationpublic 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 存贮的对比一致,则是同一个会话。

用户头像

Rubble

关注

还未添加个人签名 2021.06.01 加入

还未添加个人简介

评论

发布
暂无评论
分布式session之RedisSession的探索_redis_Rubble_InfoQ写作平台