1.搭建测试环境

img

引入maven

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/>
</parent>

<groupId>com.easysession</groupId>
<artifactId>easysession</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<skipTests>true</skipTests>

<springboot.version>2.6.1</springboot.version>
<logback.version>1.2.10</logback.version>
<jwt.version>3.2.0</jwt.version>
<fastjson.version>1.2.66</fastjson.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${springboot.version}</version>
</dependency>

<!-- 日志版本 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>

<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>

</dependencies>


<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.6.RELEASE</version>
<configuration>
<mainClass>com.reconciliation.RunApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>

引入logback-spring.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="10 minutes">
<appender name="stdot" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss,GMT+8} [%p][%c][%M][%L]-> %m%n</pattern>
</layout>
</appender>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>easysession.log</file>
<encoder>
<charset>utf-8</charset>
<pattern>%d{yyyy-MM-dd HH:mm:ss,GMT+8} [%p][%c][%M][%L]-> %m%n</pattern>
</encoder>
<append>false</append>
<prudent>false</prudent>
</appender>

<root level="info">
<appender-ref ref="stdot"/>
<appender-ref ref="file"/>
</root>
</configuration>

配置文件

application.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 应用服务 WEB 访问端口
server.port=5050
#session过期时间 60M 一个小时
server.servlet.session.timeout=PT60M
#错误页处理
spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false
#Spring redis配置
# Redis数据库索引(默认为0)
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=20
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=2000

TestController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package com.easysession.controller;

import com.easysession.jwt.JWTUtil;
import com.easysession.redis.RedisUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.UUID;

/**
* @ClassName TestController
* @Description TODO
* @Author Administrator
* @Date 2023/12/16 16:22
*/
@RestController
public class TestController {

private static final String SESSION_KEY="session_key";

private static final String JWT_KEY ="jwt_key";

@Resource
private RedisUtils redisUtils;

@Resource
private JWTUtil<String> jwtUtil;

private boolean isEmpty(String value){
if(null==value||"".equals(value.trim())){
return true;
}
return false;
}

@RequestMapping("saveSessionInfo")
public String saveSessionInfo(HttpSession session,String msg){
if(isEmpty(msg)){
return "msg不能为空";
}
session.setAttribute(SESSION_KEY,msg);
return "保存session信息成功,sessionId:"+session.getId();
}

@RequestMapping("getSessionInfo")
public String getSessionInfo(HttpSession session){
return "获取的session信息为:"+session.getAttribute(SESSION_KEY);
}

@RequestMapping("saveByToken")
public String saveByToken(String msg){
if(isEmpty(msg)){
return "msg不能为空";
}
String token = UUID.randomUUID().toString();
redisUtils.set(token,msg);
return "保存token信息成功,token:"+token;
}

@RequestMapping("getByToken")
public String getByToken(String token){
if(isEmpty(token)){
return "token不能为空";
}
return "获取的token信息为:"+redisUtils.get(token);
}

@RequestMapping("saveByTokenWithCookie")
public String saveByTokenWithCookie(HttpServletResponse response,String msg){
if(isEmpty(msg)){
return "msg不能为空";
}
String token = UUID.randomUUID().toString();
redisUtils.set(token,msg);
Cookie cookie = new Cookie("token",token);
//cookie.setMaxAge(10);
response.addCookie(cookie);
return "保存token信息成功,token:"+token;
}

@RequestMapping("getByTokenWithCookie")
public String getByTokenWithCookie(HttpServletRequest request){
Cookie[] cookies = request.getCookies();
if(cookies==null){
return "获取的token信息为:null";
}
String token = null;
for (Cookie cookie:cookies){
if("token".equals(cookie.getName())){
token = cookie.getValue();
break;
}
}
if(isEmpty(token)){
return "token不能为空";
}
return "获取的token信息为:"+redisUtils.get(token);
}

@RequestMapping("saveByJwt")
public String saveByJwt(String msg){
if(isEmpty(msg)){
return "msg不能为空";
}
String token =jwtUtil.createToken(JWT_KEY,msg,10000);
return "保存token信息成功,token:"+token;
}


@RequestMapping("getByJwt")
public String getByJwt(String token){
if(isEmpty(token)){
return "token不能为空";
}
String msg =jwtUtil.getTokenData(JWT_KEY,token,String.class);
return "获取jwt的信息是"+msg;
}
}

JsonUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.easysession.jwt;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

public class JsonUtils {
private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);

public static String convertObj2Json(Object obj) {
return JSON.toJSONString(obj);
}

public static <T> T convertJson2Obj(String json, Class<T> classz) {
try {
return JSONObject.parseObject(json, classz);
} catch (Exception e) {
logger.error("convertJson2Obj异常,json:{}", json);
throw new RuntimeException("数据转换异常");
}
}

public static <T> List<T> convertJsonArray2List(String json, Class<T> classz) {
try {
return JSONArray.parseArray(json, classz);
} catch (Exception e) {
logger.error("convertJsonArray2List,json:{}", json, e);
throw new RuntimeException("数据转换异常");
}
}
}

JWTUtil

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.easysession.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component("jwtUtil")
public class JWTUtil<T> {

private static final String SECRET = "test123456";

/**
* 签名生成
*
* @return
*/
public String createToken(String key, T data, Integer expireSeconds) {
String token = null;
try {
Date expiresAt = new Date(System.currentTimeMillis() + expireSeconds * 1000);
token = JWT.create()
.withClaim(key, JsonUtils.convertObj2Json(data))
.withExpiresAt(expiresAt)
.sign(Algorithm.HMAC256(SECRET));
} catch (Exception e) {
e.printStackTrace();
}
return token;
}

/**
* 签名验证
*
* @param token
* @return
*/
public <T> T getTokenData(String key, String token, Class<T> classz) {
try {
if (null == token || "".equals(token)) {
return null;
}
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
DecodedJWT jwt = verifier.verify(token);
String jsonData = jwt.getClaim(key).asString();
return JsonUtils.convertJson2Obj(jsonData, classz);
} catch (Exception e) {
return null;
}
}
}

RedisConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.easysession.redis;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

@Configuration("redisConfig")
public class RedisConfig<V> {

@Bean
public RedisTemplate<String, V> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, V> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 设置key的序列化方式
template.setKeySerializer(RedisSerializer.string());
// 设置value的序列化方式
template.setValueSerializer(RedisSerializer.json());
// 设置hash的key的序列化方式
template.setHashKeySerializer(RedisSerializer.string());
// 设置hash的value的序列化方式
template.setHashValueSerializer(RedisSerializer.json());
template.afterPropertiesSet();
return template;
}
}

RedisUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package com.easysession.redis;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

@Component("redisUtils")
public class RedisUtils<V> {

@Resource
private RedisTemplate<String, V> redisTemplate;

private static final Logger logger = LoggerFactory.getLogger(RedisUtils.class);

/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
public void delete(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}

public V get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}

/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, V value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
logger.error("设置redisKey:{},value:{}失败", key, value);
return false;
}
}

/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean setex(String key, V value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
logger.error("设置redisKey:{},value:{}失败", key, value);
return false;
}
}

public long increment(String key, long delta, long time) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
long result = redisTemplate.opsForValue().increment(key, delta);
if (result == 1) {
expire(key, time);
}
return result;
}

public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}

这部分内容介绍了 Session、JWT 和 Token 的使用及区别,以下是详细的讲解:


1. Session

概念

Session 是服务器用来存储用户信息的一种方式。当用户登录时,服务器会为每个用户创建一个 Session,并将用户的相关信息保存在服务器端。客户端通过 Session ID 来访问该信息。

工作原理

  • Session ID:客户端通过 Cookie 或 URL 参数将 Session ID 发送给服务器,服务器根据该 ID 查找并返回对应的 Session 信息。
  • 存储方式:Session 通常存储在服务器的内存中(如 Redis)或者数据库中,避免了每次请求都需要传输大量的数据。

优缺点

  • 优点

    • 安全性高,因为 Session 数据存储在服务器端。
    • 不易受到客户端篡改。
  • 缺点

    • 每次访问服务器时需要携带 Session ID,可能会增加请求的负担。
    • 在负载均衡和分布式架构中,Session 数据需要共享,可能涉及到复杂的存储解决方案。

2. JWT (JSON Web Token)

概念

JWT 是一种用于客户端和服务器之间传递信息的紧凑、安全的 JSON 格式。它由三部分组成:

  1. Header(头部):包含了令牌的元数据,如签名算法。
  2. Payload(负载):包含了用户信息和其他数据。
  3. Signature(签名):用于验证令牌的有效性和防止篡改。

工作原理

  • 生成:服务器生成 JWT 后,客户端会收到该令牌,通常会将其存储在浏览器的 LocalStorageCookie 中。
  • 使用:每次请求时,客户端将 JWT 放在 HTTP 请求的 Authorization 头中发送给服务器,服务器验证签名后,获取请求的用户信息。
  • 无状态:JWT 是 无状态的,服务器不需要存储会话信息,减轻了服务器负担。

优缺点

  • 优点

    • 无状态,减轻了服务器存储压力。
    • 可以跨域使用,适合微服务架构。
  • 缺点

    • 一旦签名泄露,攻击者可以伪造 JWT,影响安全性。
    • JWT 的有效期和签名一旦生成,就不能改变,若需要更新用户信息,需要重新生成新的 JWT。

3. Token

概念

Token 是一个通用的认证方式,用于代替传统的基于 Session 的认证。与 SessionJWT 类似,Token 也是用于验证用户身份的一种方法,但与 Session 不同的是,它通常是短期有效的,且可以包含更多的信息。

工作原理

  1. 生成 Token:客户端登录时,服务器通过 用户名密码 验证用户身份,并生成 Token
  2. 存储 Token:客户端将 Token 存储在 LocalStorageCookie 中,每次请求时将其发送到服务器进行验证。
  3. 验证 Token:服务器验证 Token 的有效性并解析出用户信息。

优缺点

  • 优点

    • 简化了服务器管理,减少了对服务器端存储的依赖。
    • 可以方便地实现跨域认证。
  • 缺点

    • 需要确保 Token 的传输过程是安全的(例如通过 HTTPS),否则容易被劫持。
    • 一旦泄露,攻击者可以直接获取 Token,可能带来安全风险。

Session、JWT 和 Token 的比较

特性 Session JWT Token
存储方式 服务器端存储(内存或数据库) 客户端存储(如 LocalStorage 或 Cookie) 客户端存储(如 LocalStorage 或 Cookie)
认证方式 基于 Session ID 基于 JWT Token 基于 Token
状态性 有状态,服务器需要存储 Session 数据 无状态,数据包含在 JWT 中 无状态,数据包含在 Token 中
跨域问题 需要共享 Session 数据(复杂的配置) 可轻松实现跨域认证 同 JWT,支持跨域认证
安全性 需要保护 Session ID 和会话数据 需要保护 Token 和签名 与 JWT 相似,保护 Token 防止泄漏

总结

  1. Session:适合需要状态管理和数据存储的场景,但在分布式系统中可能会增加管理复杂性。
  2. JWT:适合无状态的分布式认证,简化了服务器的负担,适用于微服务架构,但需要特别注意安全性。
  3. Token:是一个更通用的认证方案,功能与 JWT 类似,通常与 JWT 一起使用,但需要保护 Token 的有效性和安全性。

这些身份验证机制各有优缺点,选择适合的机制取决于应用的具体需求,如性能要求、分布式架构的复杂度、安全性等。

这段代码展示了一个 Spring Boot 项目中的 TestController 类,涉及到 Session、Token(包括通过 Redis 存储的普通 Token)和 JWT 的使用。下面我将详细讲解代码的作用和每个部分的功能:


1. TestController

TestController 类提供了一些接口,演示如何使用 SessionTokenJWT 来保存和获取用户信息。它包含以下几个核心方法:

2. 主要方法解释

saveSessionInfo

1
2
3
4
5
6
7
8
@RequestMapping("saveSessionInfo")
public String saveSessionInfo(HttpSession session, String msg) {
if (isEmpty(msg)) {
return "msg不能为空";
}
session.setAttribute(SESSION_KEY, msg);
return "保存session信息成功,sessionId:" + session.getId();
}
  • 功能:此方法将用户提供的信息(msg)存储在 Session 中。Session 是服务器端保存的用户会话数据。
  • 用法:通过 session.setAttribute(SESSION_KEY, msg)msg 保存到 Session 中。
  • 返回值:返回成功信息和当前的 sessionId

getSessionInfo

1
2
3
4
@RequestMapping("getSessionInfo")
public String getSessionInfo(HttpSession session) {
return "获取的session信息为:" + session.getAttribute(SESSION_KEY);
}
  • 功能:此方法从 Session 中获取之前保存的 msg 信息。
  • 用法:通过 session.getAttribute(SESSION_KEY) 获取存储在 Session 中的信息。

saveByToken

1
2
3
4
5
6
7
8
9
@RequestMapping("saveByToken")
public String saveByToken(String msg) {
if (isEmpty(msg)) {
return "msg不能为空";
}
String token = UUID.randomUUID().toString();
redisUtils.set(token, msg);
return "保存token信息成功,token:" + token;
}
  • 功能:将 msg 信息保存到 Redis 中,并生成一个随机的 Token(UUID),将其与 msg 一起存储。
  • 用法:通过 Redis 工具类 redisUtils.set(token, msg) 将 Token 和消息一起存入 Redis。
  • 返回值:返回成功信息和生成的 Token。

getByToken

1
2
3
4
5
6
7
@RequestMapping("getByToken")
public String getByToken(String token) {
if (isEmpty(token)) {
return "token不能为空";
}
return "获取的token信息为:" + redisUtils.get(token);
}
  • 功能:通过传入 Token 从 Redis 中获取对应的消息 msg
  • 用法:通过 redisUtils.get(token) 获取保存在 Redis 中与 Token 关联的 msg
  • 返回值:返回获取到的信息。

saveByTokenWithCookie

1
2
3
4
5
6
7
8
9
10
11
@RequestMapping("saveByTokenWithCookie")
public String saveByTokenWithCookie(HttpServletResponse response, String msg) {
if (isEmpty(msg)) {
return "msg不能为空";
}
String token = UUID.randomUUID().toString();
redisUtils.set(token, msg);
Cookie cookie = new Cookie("token", token);
response.addCookie(cookie);
return "保存token信息成功,token:" + token;
}
  • 功能:与 saveByToken 类似,但这里将 Token 信息存入浏览器的 Cookie 中。这样可以在后续请求中通过 Cookie 自动携带 Token 信息。
  • 用法:通过 response.addCookie(cookie) 将生成的 Token 保存到客户端的 Cookie 中。

getByTokenWithCookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RequestMapping("getByTokenWithCookie")
public String getByTokenWithCookie(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies == null) {
return "获取的token信息为:null";
}
String token = null;
for (Cookie cookie : cookies) {
if ("token".equals(cookie.getName())) {
token = cookie.getValue();
break;
}
}
if (isEmpty(token)) {
return "token不能为空";
}
return "获取的token信息为:" + redisUtils.get(token);
}
  • 功能:从请求中获取 Cookie 中的 Token,然后使用 Redis 获取与该 Token 相关联的消息。
  • 用法:通过 request.getCookies() 获取请求中的 Cookie,并获取 Token。

saveByJwt

1
2
3
4
5
6
7
8
@RequestMapping("saveByJwt")
public String saveByJwt(String msg) {
if (isEmpty(msg)) {
return "msg不能为空";
}
String token = jwtUtil.createToken(JWT_KEY, msg, 10000);
return "保存token信息成功,token:" + token;
}
  • 功能:生成一个 JWT 并将 msg 数据保存在 JWT 中,返回 JWT Token。
  • 用法:通过 jwtUtil.createToken(JWT_KEY, msg, 10000) 创建一个 JWT,其中 10000 表示该 Token 的有效期(单位为秒)。
  • 返回值:返回成功信息和生成的 JWT。

getByJwt

1
2
3
4
5
6
7
8
@RequestMapping("getByJwt")
public String getByJwt(String token) {
if (isEmpty(token)) {
return "token不能为空";
}
String msg = jwtUtil.getTokenData(JWT_KEY, token, String.class);
return "获取jwt的信息是" + msg;
}
  • 功能:验证并解析传入的 JWT,获取其中的数据(msg)。
  • 用法:通过 jwtUtil.getTokenData(JWT_KEY, token, String.class) 获取 JWT 中保存的数据。

3. 总结

  • Session:用来存储用户会话信息,保存在服务器端,通过 sessionId 来标识每个用户会话。
  • Token:通常用来进行无状态认证。通过生成一个唯一的字符串(如 UUID),并将其存储在 Redis 中。Token 可以通过 Cookie 或请求头传递。
  • JWT:一种基于 Token 的认证方式,但它具有内嵌的签名,保证数据不被篡改,并支持跨域认证。JWT 的好处是无状态、跨平台,且支持一定的有效期。

在这段代码中,TestController 展示了如何使用 SessionTokenJWT 来管理用户的身份信息。RedisUtils 用于与 Redis 进行交互,JWTUtil 则是用来生成和验证 JWT Token 的工具类。