分布式RedisSession的探索

举报
琴岛蛏子 发表于 2022/03/21 00:02:53 2022/03/21
【摘要】 分布式RedisSession的探索​ 为什么需要分布式session,对于API接口是不需要session的,对于后台管理页面,基于session的认证及授权如shiro是需要分布式session的。​ spring cloud常用的分布式session解决方案redisSession是基于cookie来存贮session的,对于前后端分离的项目,可以在请求中携带cookie。 1. 搭...

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

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。