11-SpringSecurity:Session共享

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 11-SpringSecurity:Session共享

背景


本系列教程,是作为团队内部的培训资料准备的。主要以实验的方式来体验 SpringSecurity 的各项Feature。


分布式集群架构下的 Session 共享一般有以下几种实现方案:


  • Session 复制


集群中任一服务器上的 Session 发生变化(增删改),该节点会把这个 Session 的所有内容序列化,然后广播给所有其它节点,从而实现 Session 同步。


  • Session 粘滞


利用 Ngnix 负载均衡策略中的 ip_hash 机制,将某个 ip 的所有请求都定向到同一台服务器上,即定向流量分发,这个其实不存在Session共享,仅是实现了用户请求与某个服务的绑定。


  • Session 持久化


将所有的 Session 集中存储,存储到数据库中,保证 Session 的持久化,但是我们知道,随着用户数据量(活跃)的增加,查询数据库开销也随之增加。


  • Session 共享


将所有的 Session 集中存储,可使用分布式缓存方案比如 Redis 来缓存 Session ,实现 Session 共享,查询效率高,同时可以横向扩展。


显然,上述四种方案实际中应用更多的是最后一种:基于分布式缓存(eg: Memcached, Redis)的Session共享,我们今天就演示这种方案。


新建一个 SpringBoot 项目,起名 springboot-security-session ,核心依赖为 Web , SpringSecurity , SpringSessionRedis


  • pom依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <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>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
  • 配置文件
server:
  port: 8000
spring:
  redis:
    host: 10.16.1.110
    port: 6379
    pool.max-idle: 8
    pool.min-idle: 0
    pool.max-active: 8
    pool.max-wait: -1
    password:
    timeout: 1000
  • 资源接口


创建资源接口: 登录之后默认跳转 / ,展示当前服务的端口号。

@RestController
public class SessionController {
  @Value("${server.port}")
  Integer port;
  @GetMapping(value = "/")
  public String greeting() {
    return String.valueOf(port);
  }
}


实验0:伪分布式集群Session共享


开启两个服务:


  1. 一个运行在8000端口:http://localhost:8000

  1. 一个运行在9000端口:http://localhost:9000

Note:在Idea中,可通过以下配置可同时运行一个服务的多个实例。

image.png

实验步骤:


  1. 在浏览器中先访问 http://localhost:8000 ,这时要求登录,输入用户名:user,密码在控制台生成;登录成功后显示: 8000


  1. 然后继续在当前浏览器新开一个Tab,访问 http://localhost:9000 ,不出意外,会直接显示(无需再次登录): 9000


  1. 这样,便通过一个依赖 spring-session-data-redis 实现了 Session 共享(就不贴图了);


Note:


  • 由于仍然采用的传统的 Cookie-Session 模式,所以上述实验必须在同一浏览器下进行,在请求时,浏览器会自动带上 Cookie (其中存了SessionID);


  • 实际生产中,通常通过Nginx进行反向代理,仅对外提供一个域名或接口地址,实现集群的负载均衡;


实验1:再次验证Session共享


Controller 中新增两个接口:一个写入键值对,一个读取键值,接口如下:

@RestController
public class SessionController {
  @Value("${server.port}")
  Integer port;
  @GetMapping(value = "/")
  public String greeting() {
    return String.valueOf(port);
  }
  @GetMapping(value = "/session/set")
  public String setSession(HttpSession session) {
    session.setAttribute("key", "value");
    return port + ": Session updated.";
  }
  @GetMapping(value = "/session/get")
  public String getSession(HttpSession session) {
    Object value = session.getAttribute("key");
    return port + ":" + (String) value;
  }
}

实验步骤:


  1. 在浏览器中先访问 http://localhost:8000/session/set ,这时显示: 8000: Session updated.


  1. 然后继续在当前浏览器新开一个Tab,访问 http://localhost:9000/session/get ,不出意外,会显示: 9000:value


  1. 这样,实现了自定义键值对的 Session 共享;


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
存储 NoSQL Java
Spring Session分布式会话管理
Spring Session分布式会话管理
97 0
|
SQL JSON 安全
Spring Authorization Server OAuth2授权服务器配置详解
Spring Authorization Server OAuth2授权服务器配置详解
3212 0
|
前端开发 JavaScript Java
SpringBoot Ajax跨域问题(session共享问题)
ajax 发送post请求至springBoot出现跨域问题 需要在springBoot加上注解 @CrossOrigin 就能解决
64 0
|
6月前
|
安全 搜索推荐 Java
【SpringSecurity6.x】会话管理
【SpringSecurity6.x】会话管理
84 0
|
存储 NoSQL Java
SpringSecurity-12-Redis实现基于session共享登录方案
如果我们使用单机版本的Session存储身份信息的时候,如果服务器挂掉,那么服务就无法使用了。如果我们将项目部署到CD两台服务器上,Session就无法保持一致。如果用户user第一次访问C服务器,然后再次请求的时候访问D服务器,但是B没有存储user的session,这样用户就需要重新登录。 所以为了解决这种情况,我们可以将session放到redis中,以后用户请求都可以从redis中获取session,从而保持登录二点一致性。
295 1
|
安全 Java 数据安全/隐私保护
SpringSecurity-10-Session会话管理
SpringSecurity-10-Session会话管理
135 0
|
负载均衡 安全 NoSQL
spring security 在没实现session共享的集群环境下 防止用户多次登录的 实现思路
spring security 在没实现session共享的集群环境下 防止用户多次登录的 实现思路
271 0
|
存储 SQL 编解码
Spring Security系列教程16--基于持久化令牌方案实现自动登录
前言 在上一章节中,一一哥 带各位基于散列加密方案实现了自动登录,并且给各位介绍了散列加密算法,其实还有另一种自动登录的实现方案,也就是基于持久化令牌方案来进行实现。接下来请跟 一一哥 学习这种方案该怎么实现吧。 一. 持久化令牌方案简介 1. 持久化令牌方案 有的小伙伴会问,既然我们要基于持久化令牌来实现自动登录,那啥是持久化令牌啊?所以 一一哥 先给大家做个概念解释。 所谓的持久化令牌的实现方案,其实在交互上与我们前面章节讲的散列加密方案一致,只不过是在用户勾选Remember-me之后,将生成的token令牌发送到用户浏览器,并在用户下次访问系统时读取该令牌进行认证。不同的是,持久化令
515 0
|
存储 NoSQL 安全
Spring Security系列教程21--会话管理之实现集群会话
前言 现在我们已经掌握了如何防御会话固定攻击,处理会话过期,对会话进行并发控制等,但是这些会话处理手段都是针对单机环境下的,在现在的大型项目中,很多时候都是采用分布式开发方案。一旦涉及到分布式方案,就意味着我们的服务器可能会有多台,而我们的项目也可能会根据业务被拆分成了若干个子服务,每个服务又可能被部署在不同的服务器上。这时候问题就来了,以前单台服务器的时候,我们的会话很好管理,现在有多台服务器,那会话岂不是有多个了?这时候我们把服务器集群环境下的会话和单个用户关联起来? 啊啊啊...是不是感觉很复杂! 别害怕!Spring Security其实给我们提供了对应的解决方案,就是 一一哥 今
411 0
|
XML 存储 缓存
Shiro - Spring + Jedis(会话、缓存、自动登录)整合篇(上)
Shiro - Spring + Jedis(会话、缓存、自动登录)整合篇(上)
306 0
Shiro - Spring + Jedis(会话、缓存、自动登录)整合篇(上)