2021-10-21 01:09:31 +08:00
|
|
|
|
# 和 jwt 集成
|
|
|
|
|
|
|
|
|
|
本插件的作用是让 Sa-Token 和 jwt 做一个整合。
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### 1、引入依赖
|
|
|
|
|
首先在项目已经引入 Sa-Token 的基础上,继续添加:
|
|
|
|
|
|
2022-10-20 13:06:36 +08:00
|
|
|
|
<!---------------------------- tabs:start ---------------------------->
|
|
|
|
|
<!-------- tab:Maven 方式 -------->
|
|
|
|
|
``` xml
|
2021-10-30 00:37:04 +08:00
|
|
|
|
<!-- Sa-Token 整合 jwt -->
|
2021-10-21 01:09:31 +08:00
|
|
|
|
<dependency>
|
|
|
|
|
<groupId>cn.dev33</groupId>
|
|
|
|
|
<artifactId>sa-token-jwt</artifactId>
|
|
|
|
|
<version>${sa.top.version}</version>
|
|
|
|
|
</dependency>
|
|
|
|
|
```
|
2022-10-20 13:06:36 +08:00
|
|
|
|
<!-------- tab:Gradle 方式 -------->
|
|
|
|
|
``` gradle
|
|
|
|
|
// Sa-Token 整合 jwt
|
|
|
|
|
implementation 'cn.dev33:sa-token-jwt:${sa.top.version}'
|
|
|
|
|
```
|
|
|
|
|
<!---------------------------- tabs:end ---------------------------->
|
|
|
|
|
|
|
|
|
|
|
2024-07-29 00:43:55 +08:00
|
|
|
|
> [!WARNING| label:版本兼容性]
|
2023-04-26 12:52:56 +08:00
|
|
|
|
> 1. 注意: sa-token-jwt 显式依赖 hutool-jwt 5.7.14 版本,保险起见:你的项目中要么不引入 hutool,要么引入版本 >= 5.7.14 的 hutool 版本。
|
|
|
|
|
> 2. hutool 5.8.13 和 5.8.14 版本下会出现类型转换问题,[关联issue](https://gitee.com/dromara/sa-token/issues/I6L429)。
|
2021-10-21 01:09:31 +08:00
|
|
|
|
|
2023-03-09 10:43:05 +08:00
|
|
|
|
|
2021-10-21 01:09:31 +08:00
|
|
|
|
### 2、配置秘钥
|
|
|
|
|
在 `application.yml` 配置文件中配置 jwt 生成秘钥:
|
2022-10-20 13:06:36 +08:00
|
|
|
|
|
|
|
|
|
<!---------------------------- tabs:start ---------------------------->
|
|
|
|
|
<!------------- tab:yaml 风格 ------------->
|
|
|
|
|
``` yaml
|
2021-10-21 01:09:31 +08:00
|
|
|
|
sa-token:
|
|
|
|
|
# jwt秘钥
|
|
|
|
|
jwt-secret-key: asdasdasifhueuiwyurfewbfjsdafjk
|
|
|
|
|
```
|
2022-10-20 13:06:36 +08:00
|
|
|
|
<!------------- tab:properties 风格 ------------->
|
|
|
|
|
``` properties
|
|
|
|
|
# jwt秘钥
|
|
|
|
|
sa-token.jwt-secret-key: asdasdasifhueuiwyurfewbfjsdafjk
|
|
|
|
|
```
|
|
|
|
|
<!---------------------------- tabs:end ---------------------------->
|
|
|
|
|
|
2021-10-21 01:09:31 +08:00
|
|
|
|
注:为了安全起见请不要直接复制官网示例这个字符串(随便按几个字符就好了)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 3、注入jwt实现
|
|
|
|
|
根据不同的整合规则,插件提供了三种不同的模式,你需要 **选择其中一种** 注入到你的项目中
|
|
|
|
|
|
|
|
|
|
<!------------------------------ tabs:start ------------------------------>
|
|
|
|
|
|
2022-05-01 04:46:28 +08:00
|
|
|
|
<!-- tab: Simple 简单模式 -->
|
|
|
|
|
Simple 模式:Token 风格替换
|
2021-10-21 01:09:31 +08:00
|
|
|
|
``` java
|
|
|
|
|
@Configuration
|
|
|
|
|
public class SaTokenConfigure {
|
2022-05-01 04:46:28 +08:00
|
|
|
|
// Sa-Token 整合 jwt (Simple 简单模式)
|
2021-10-21 01:09:31 +08:00
|
|
|
|
@Bean
|
|
|
|
|
public StpLogic getStpLogicJwt() {
|
2022-05-01 04:46:28 +08:00
|
|
|
|
return new StpLogicJwtForSimple();
|
2021-10-21 01:09:31 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-05-01 04:46:28 +08:00
|
|
|
|
<!-- tab: Mixin 混入模式 -->
|
|
|
|
|
Mixin 模式:混入部分逻辑
|
2021-10-21 01:09:31 +08:00
|
|
|
|
``` java
|
|
|
|
|
@Configuration
|
|
|
|
|
public class SaTokenConfigure {
|
2022-05-01 04:46:28 +08:00
|
|
|
|
// Sa-Token 整合 jwt (Mixin 混入模式)
|
2021-10-21 01:09:31 +08:00
|
|
|
|
@Bean
|
|
|
|
|
public StpLogic getStpLogicJwt() {
|
2022-05-01 04:46:28 +08:00
|
|
|
|
return new StpLogicJwtForMixin();
|
2021-10-21 01:09:31 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-05-01 04:46:28 +08:00
|
|
|
|
<!-- tab: Stateless 无状态模式 -->
|
2021-10-21 01:09:31 +08:00
|
|
|
|
Stateless 模式:服务器完全无状态
|
|
|
|
|
``` java
|
|
|
|
|
@Configuration
|
|
|
|
|
public class SaTokenConfigure {
|
2022-05-01 04:46:28 +08:00
|
|
|
|
// Sa-Token 整合 jwt (Stateless 无状态模式)
|
2021-10-21 01:09:31 +08:00
|
|
|
|
@Bean
|
|
|
|
|
public StpLogic getStpLogicJwt() {
|
|
|
|
|
return new StpLogicJwtForStateless();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!---------------------------- tabs:end ------------------------------>
|
|
|
|
|
|
|
|
|
|
### 4、开始使用
|
|
|
|
|
然后我们就可以像之前一样使用 Sa-Token 了
|
|
|
|
|
``` java
|
|
|
|
|
/**
|
|
|
|
|
* 登录测试
|
|
|
|
|
*/
|
|
|
|
|
@RestController
|
|
|
|
|
@RequestMapping("/acc/")
|
|
|
|
|
public class LoginController {
|
|
|
|
|
|
|
|
|
|
// 测试登录
|
|
|
|
|
@RequestMapping("login")
|
|
|
|
|
public SaResult login() {
|
|
|
|
|
StpUtil.login(10001);
|
|
|
|
|
return SaResult.ok("登录成功");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查询登录状态
|
|
|
|
|
@RequestMapping("isLogin")
|
|
|
|
|
public SaResult isLogin() {
|
|
|
|
|
return SaResult.ok("是否登录:" + StpUtil.isLogin());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 测试注销
|
|
|
|
|
@RequestMapping("logout")
|
|
|
|
|
public SaResult logout() {
|
|
|
|
|
StpUtil.logout();
|
|
|
|
|
return SaResult.ok();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
访问上述接口,观察Token生成的样式
|
|
|
|
|
``` java
|
|
|
|
|
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbklkIjoiMTAwMDEiLCJybiI6IjZYYzgySzBHVWV3Uk5NTTl1dFdjbnpFZFZHTVNYd3JOIn0.F_7fbHsFsDZmckHlGDaBuwDotZwAjZ0HB14DRujQfOQ
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-08 16:05:54 +08:00
|
|
|
|
|
2022-07-05 18:52:34 +08:00
|
|
|
|
### 5、不同模式策略对比
|
2021-10-21 01:09:31 +08:00
|
|
|
|
|
|
|
|
|
注入不同模式会让框架具有不同的行为策略,以下是三种模式的差异点(为方便叙述,以下比较以同时引入 jwt 与 Redis 作为前提):
|
|
|
|
|
|
2022-05-01 04:46:28 +08:00
|
|
|
|
| 功能点 | Simple 简单模式 | Mixin 混入模式 | Stateless 无状态模式 |
|
2021-10-21 01:09:31 +08:00
|
|
|
|
| :-------- | :-------- | :-------- | :-------- |
|
|
|
|
|
| Token风格 | jwt风格 | jwt风格 | jwt风格 |
|
2023-03-02 08:57:10 +08:00
|
|
|
|
| 登录数据存储 | Redis中存储 | Token中存储 | Token中存储 |
|
|
|
|
|
| Session存储 | Redis中存储 | Redis中存储 | 无Session |
|
2021-10-21 01:09:31 +08:00
|
|
|
|
| 注销下线 | 前后端双清数据 | 前后端双清数据 | 前端清除数据 |
|
|
|
|
|
| 踢人下线API | 支持 | 不支持 | 不支持 |
|
2022-10-24 18:51:52 +08:00
|
|
|
|
| 顶人下线API | 支持 | 不支持 | 不支持 |
|
2021-10-21 01:09:31 +08:00
|
|
|
|
| 登录认证 | 支持 | 支持 | 支持 |
|
|
|
|
|
| 角色认证 | 支持 | 支持 | 支持 |
|
|
|
|
|
| 权限认证 | 支持 | 支持 | 支持 |
|
|
|
|
|
| timeout 有效期 | 支持 | 支持 | 支持 |
|
2023-06-06 06:18:52 +08:00
|
|
|
|
| active-timeout 有效期 | 支持 | 支持 | 不支持 |
|
2021-10-21 01:09:31 +08:00
|
|
|
|
| id反查Token | 支持 | 支持 | 不支持 |
|
|
|
|
|
| 会话管理 | 支持 | 部分支持 | 不支持 |
|
|
|
|
|
| 注解鉴权 | 支持 | 支持 | 支持 |
|
2022-03-16 16:51:14 +08:00
|
|
|
|
| 路由拦截鉴权 | 支持 | 支持 | 支持 |
|
2021-10-21 01:09:31 +08:00
|
|
|
|
| 账号封禁 | 支持 | 支持 | 不支持 |
|
|
|
|
|
| 身份切换 | 支持 | 支持 | 支持 |
|
|
|
|
|
| 二级认证 | 支持 | 支持 | 支持 |
|
|
|
|
|
| 模式总结 | Token风格替换 | jwt 与 Redis 逻辑混合 | 完全舍弃Redis,只用jwt |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-07-05 18:52:34 +08:00
|
|
|
|
### 6、扩展参数
|
|
|
|
|
你可以通过以下方式在登录时注入扩展参数:
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
// 登录10001账号,并为生成的 Token 追加扩展参数name
|
2025-04-02 01:09:07 +08:00
|
|
|
|
StpUtil.login(10001, new SaLoginParameter().setExtra("name", "zhangsan"));
|
2022-07-05 18:52:34 +08:00
|
|
|
|
|
|
|
|
|
// 连缀写法追加多个
|
2025-04-02 01:09:07 +08:00
|
|
|
|
StpUtil.login(10001, new SaLoginParameter()
|
2022-07-05 18:52:34 +08:00
|
|
|
|
.setExtra("name", "zhangsan")
|
|
|
|
|
.setExtra("age", 18)
|
|
|
|
|
.setExtra("role", "超级管理员"));
|
|
|
|
|
|
|
|
|
|
// 获取扩展参数
|
|
|
|
|
String name = StpUtil.getExtra("name");
|
2022-08-08 23:03:58 +08:00
|
|
|
|
|
|
|
|
|
// 获取任意 Token 的扩展参数
|
|
|
|
|
String name = StpUtil.getExtra("tokenValue", "name");
|
2022-07-05 18:52:34 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 7、在多账户模式中集成 jwt
|
|
|
|
|
sa-token-jwt 插件默认只为 `StpUtil` 注入 `StpLogicJwtFoxXxx` 实现,自定义的 `StpUserUtil` 是不会自动注入的,我们需要帮其手动注入:
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
/**
|
|
|
|
|
* 为 StpUserUtil 注入 StpLogicJwt 实现
|
|
|
|
|
*/
|
2024-04-12 12:46:21 +08:00
|
|
|
|
@PostConstruct
|
2022-07-05 18:52:34 +08:00
|
|
|
|
public void setUserStpLogic() {
|
2022-08-08 17:47:00 +08:00
|
|
|
|
StpUserUtil.setStpLogic(new StpLogicJwtForSimple(StpUserUtil.TYPE));
|
2022-07-05 18:52:34 +08:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-08-22 16:30:12 +08:00
|
|
|
|
### 8、自定义 SaJwtUtil 生成 token 的算法
|
|
|
|
|
|
|
|
|
|
如果需要自定义生成 token 的算法(例如更换sign方式),直接重写 SaJwtTemplate 对象即可:
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
/**
|
|
|
|
|
* 自定义 SaJwtUtil 生成 token 的算法
|
|
|
|
|
*/
|
2024-04-12 12:46:21 +08:00
|
|
|
|
@PostConstruct
|
2022-08-22 16:30:12 +08:00
|
|
|
|
public void setSaJwtTemplate() {
|
|
|
|
|
SaJwtUtil.setSaJwtTemplate(new SaJwtTemplate() {
|
|
|
|
|
@Override
|
|
|
|
|
public String generateToken(JWT jwt, String keyt) {
|
|
|
|
|
System.out.println("------ 自定义了 token 生成算法");
|
|
|
|
|
return super.generateToken(jwt, keyt);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
```
|
2023-01-10 16:35:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 9、注意点
|
|
|
|
|
|
|
|
|
|
##### 1、使用 jwt-simple 模式后,is-share=false 恒等于 false。
|
|
|
|
|
|
|
|
|
|
`is-share=true` 的意思是每次登录都产生一样的 token,这种策略和 [ 为每个 token 单独设定 setExtra 数据 ] 不兼容的,
|
|
|
|
|
为保证正确设定 Extra 数据,当使用 `jwt-simple` 模式后,`is-share` 配置项 恒等于 `false`。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##### 2、使用 jwt-mixin 模式后,is-concurrent 必须为 true。
|
|
|
|
|
|
|
|
|
|
`is-concurrent=false` 代表每次登录都把旧登录顶下线,但是 jwt-mixin 模式登录的 token 并不会记录在持久库数据中,
|
|
|
|
|
技术上来讲无法将其踢下线,所以此时顶人下线和踢人下线等 API 都属于不可用状态,所以此时 `is-concurrent` 配置项必须配置为 `true`。
|
|
|
|
|
|
|
|
|
|
|
2023-04-30 23:02:04 +08:00
|
|
|
|
##### 3、使用 jwt-mixin 模式后,max-try-times 恒等于 -1。
|
|
|
|
|
|
|
|
|
|
为防止框架错误判断 token 唯一性,当使用 jwt-mixin 模式后,`max-try-times` 恒等于 -1。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-01-10 16:35:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|