《SpringSecurity in Action》二: 基于redis实现session共享

1 概述

这一篇基于《SpringSecurity in Action》一: 基于Session实现登陆认证的简单实现

SpringSecurity基于session实现登陆认证时,有一个问题就是无法实现分布式部署,因为session是存储在某一个节点(或是某一个服务副本)的内存里的。如有这么一个用户服务,有三个副本,当进行登陆时,登陆请求打在了副本1,而进行用户列表请求时,请求打在了副本2,这时副本2是没有副本1内存中的session信息的,所以请求会失败。这当然是一个不折不扣的BUG。
多副本问题

2 方案

针对该问题,目前有三种解决方案:

  • Session固定: 看有些地方也叫Session粘滞。这里的Session固定跟固定Session攻击可不是一个概念,这里是指根据算法,把某个用户登陆时,请求打在了哪个副本上,以后就让它的请求永远都打在这个副本上,这样就不会出现登陆打在副本1,其它接口打在副本2的情况了。这种方案的缺点就是可能会造成负载不均衡。

  • Session同步: 这种方案是当登陆完成后,把副本1里的session对接同步到其它副本上去,一看就知道会面临数据一致性问题,而且副本多的话,这个问题会越发明显。

  • Session共享: 这种方案是当登陆完成后,处理登陆请求的那个副本,把sessin信息放到一个共享的存储位置,其它副本可以从这个位置读取到某用户的session信息。这个方案会不会存在数据一致性问题,就在于向共享存储写session信息时,是同步的还是异步的。如果是异步的,就会存在数据一致性问题。不过话又说回来,我们为什么要把这个操作设计成异步呢?完全没有必要没有困难制造困难也要上嘛。使用内存型的共享存储,同步延时可以很小的嘛。相信不会有人把业务服务器部署在北京,然后共享存储部署了深圳吧。

session固定示意图
在这里插入图片描述
session同步示意图
在这里插入图片描述
session共享示意图
在这里插入图片描述

3 方案选择

目前使用比较多的方案是Session共享,Session固定跟Session同步两种方案我个人并没有实践过,所以这里只说Session共享这一种方案。

虽然Session共享的原理很简单,但我们依然没有必须自己去实现一套这样的方案来,Spring已经提供了这种方案的实现。对应的是 spring-session-data-redis.
主要依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <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>
    </dependencies>

spring-session-data-redis依赖引入后,SpringBoot会自动整合以Redis为共享存储的Session共享方案,要是不放心,也可以再加个注解@EnableRedisHttpSession在启动类或是其它配置类上。

配置文件

spring:
  redis:
    host: 256.73.82.27 # 地址,这个ip是瞎写的,第一位是256就不可能的对吧
    port: 6379 # 端口
    database: 1 # 数据库索引
    password: redis

  session:
    store-type: redis

这样,引入依赖,加上配置项,就差不多完成Session共享的开发工作了。接下来测试一下。启动项目,登陆一下,效果如下:
在这里插入图片描述

登陆完成后,在redis中会出现四条记录,这表示Session已经共享到了redis中。

我是在IDEA中进行测试的,把我的测试过程说一下:

  • 启动第一个服务,端口号是8765,在8765这个服务上进行登陆操作。
  • 启动第二个服务,端口号是8766,在8766上查询业务接口。
  • 在8766这个服务上能得到正确响应。

不要担心,在本机IDEA上,把同一个服务启起来两个端口号,这跟分布式部署在本质上是一模一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值