mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-09-23 04:23:36 +08:00
优化文档
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.action.SaTokenActionDefaultImpl;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* 继承Sa-Token行为Bean默认实现, 重写部分逻辑
|
||||
*/
|
||||
@Component
|
||||
public class MySaTokenAction extends SaTokenActionDefaultImpl {
|
||||
// 重写token生成策略
|
||||
@Override
|
||||
public String createToken(Object loginId, String loginType) {
|
||||
return SaFoxUtil.getRandomString(60); // 随机60位字符串
|
||||
}
|
||||
}
|
@@ -16,17 +16,19 @@
|
||||
- [框架配置](/use/config)
|
||||
|
||||
- **深入**
|
||||
- [持久层扩展(集成Redis)](/use/dao-extend)
|
||||
- [无Cookie模式(前后台分离)](/use/not-cookie)
|
||||
- [花式token](/use/token-style)
|
||||
- [Token前缀](/use/token-prefix)
|
||||
- [记住我模式](/use/remember-me)
|
||||
- [模拟他人 & 身份切换](/use/mock-person)
|
||||
- [同端互斥登录](/use/mutex-login)
|
||||
- [二级认证](/use/safe-auth)
|
||||
- [密码加密](/use/password-secure)
|
||||
- [会话治理](/use/search-session)
|
||||
- [全局侦听器](/use/global-listener)
|
||||
<!-- - [持久层扩展(集成Redis)](/use/dao-extend) -->
|
||||
- [集成Redis](/up/integ-redis)
|
||||
<!-- - [无Cookie模式(前后台分离)](/use/not-cookie) -->
|
||||
- [前后台分离](/up/not-cookie)
|
||||
- [自定义Token风格](/up/token-style)
|
||||
- [自定义Token前缀](/up/token-prefix)
|
||||
- [记住我模式](/up/remember-me)
|
||||
- [模拟他人 & 身份切换](/up/mock-person)
|
||||
- [同端互斥登录](/up/mutex-login)
|
||||
- [二级认证](/up/safe-auth)
|
||||
- [密码加密](/up/password-secure)
|
||||
- [会话治理](/up/search-session)
|
||||
- [全局侦听器](/up/global-listener)
|
||||
|
||||
- **进阶**
|
||||
- [全局过滤器](/use/global-filter)
|
||||
|
@@ -11,7 +11,7 @@
|
||||
|
||||
### 自定义侦听器实现
|
||||
|
||||
新建`MySaTokenListener.java`,继承`SaTokenListener`接口, 并添加上注解`@Component`,保证此类被`SpringBoot`扫描到
|
||||
新建`MySaTokenListener.java`,继承`SaTokenListener`接口,并添加上注解`@Component`,保证此类被`SpringBoot`扫描到
|
||||
``` java
|
||||
/**
|
||||
* 自定义侦听器的实现
|
90
sa-token-doc/doc/up/integ-redis.md
Normal file
90
sa-token-doc/doc/up/integ-redis.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Sa-Token 集成 Redis
|
||||
---
|
||||
|
||||
Sa-token默认将数据保存在内存中,此模式读写速度最快,且避免了序列化与反序列化带来的性能消耗,但是此模式也有一些缺点,比如:
|
||||
|
||||
1. 重启后数据会丢失
|
||||
2. 无法在分布式环境中共享数据
|
||||
|
||||
为此,Sa-Token提供了扩展接口,你可以轻松将会话数据存储在 `Redis`、`Memcached`等专业的缓存中间件中,
|
||||
做到重启数据不丢失,而且保证分布式环境下多节点的会话一致性
|
||||
|
||||
以下是官方提供的Redis集成包:
|
||||
|
||||
---
|
||||
|
||||
### 1. Sa-Token 整合 Redis (使用jdk默认序列化方式)
|
||||
``` xml
|
||||
<!-- Sa-Token 整合 Redis (使用jdk默认序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis</artifactId>
|
||||
<version>${sa.top.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
优点:兼容性好,缺点:Session序列化后基本不可读,对开发者来讲等同于乱码
|
||||
|
||||
|
||||
### 2. Sa-Token 整合 Redis(使用jackson序列化方式)
|
||||
``` xml
|
||||
<!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||
<version>${sa.top.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
优点:Session序列化后可读性强,可灵活手动修改,缺点:兼容性稍差
|
||||
|
||||
|
||||
### 集成Redis请注意:
|
||||
|
||||
|
||||
**1. 无论使用哪种序列化方式,你都必须为项目提供一个Redis实例化方案,例如:**
|
||||
``` xml
|
||||
<!-- 提供redis连接池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
**2. 引入了依赖,我还需要为Redis配置连接信息吗?** <br>
|
||||
需要!只有项目初始化了正确的Redis实例,`Sa-Token`才可以使用Redis进行数据持久化,参考以下`yml配置`:
|
||||
``` java
|
||||
# 端口
|
||||
spring:
|
||||
# redis配置
|
||||
redis:
|
||||
# Redis数据库索引(默认为0)
|
||||
database: 1
|
||||
# Redis服务器地址
|
||||
host: 127.0.0.1
|
||||
# Redis服务器连接端口
|
||||
port: 6379
|
||||
# Redis服务器连接密码(默认为空)
|
||||
# password:
|
||||
# 连接超时时间(毫秒)
|
||||
timeout: 1000ms
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池最大连接数
|
||||
max-active: 200
|
||||
# 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 10
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
```
|
||||
|
||||
|
||||
**3. 集成Redis后,是我额外手动保存数据,还是框架自动保存?** <br>
|
||||
框架自动保存。集成`Redis`只需要引入对应的`pom依赖`即可,框架所有上层API保持不变
|
||||
|
||||
|
||||
<br><br>
|
||||
更多框架的集成方案正在更新中... (欢迎大家提交pr)
|
||||
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
以上介绍的api都是操作当前账号,对当前账号进行各种鉴权操作,你可能会问,我能不能对别的账号进行一些操作?<br>
|
||||
比如:查看账号`10001`有无某个权限码、获取id账号为`10002`的用户`User-Session`,等等...
|
||||
比如:查看账号10001有无某个权限码、获取 账号id=10002 的 `User-Session`,等等...
|
||||
|
||||
Sa-Token在api设计时充分考虑了这一点,暴露出多个api进行此类操作
|
||||
|
||||
@@ -46,7 +46,7 @@ StpUtil.getLoginId();
|
||||
StpUtil.endSwitch();
|
||||
```
|
||||
|
||||
你还可以: 直接在一个代码段里方法内,临时切换身份为指定loginId (此方式无需手动调用`StpUtil.endSwitch()`关闭身份切换)
|
||||
你还可以: 直接在一个代码段里方法内,临时切换身份为指定loginId(此方式无需手动调用`StpUtil.endSwitch()`关闭身份切换)
|
||||
``` java
|
||||
System.out.println("------- [身份临时切换]调用开始...");
|
||||
StpUtil.switchTo(10044, () -> {
|
@@ -7,7 +7,7 @@
|
||||
|
||||
## 具体API
|
||||
|
||||
在`Sa-Token`中如何做到同端互斥登录? <br/>
|
||||
在 Sa-Token 中如何做到同端互斥登录? <br/>
|
||||
首先在配置文件中,将 `isConcurrent` 配置为false,然后调用登录等相关接口时声明设备标识即可:
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// 指定`账号id`和`设备标识`进行登录
|
||||
StpUtil.login(10001, "PC");
|
||||
```
|
||||
调用此方法登录后,同设备的会被顶下线(不同设备不受影响),再次访问系统时会抛出 `NotLoginException` 异常,场景值=`-4`
|
||||
调用此方法登录后,同设备的会被顶下线(不同设备不受影响),再次访问系统时会抛出 `NotLoginException` 异常,场景值=`-4`
|
||||
|
||||
|
||||
#### 指定设备标识强制注销
|
||||
@@ -34,7 +34,7 @@ StpUtil.getLoginDevice();
|
||||
```
|
||||
|
||||
|
||||
#### id反查token
|
||||
#### Id 反查 Token
|
||||
``` java
|
||||
// 获取指定loginId指定设备端的tokenValue
|
||||
StpUtil.getTokenValueByLoginId(10001, "APP");
|
@@ -1,16 +1,16 @@
|
||||
# 无Cookie模式
|
||||
# 前后台分离(无Cookie模式)
|
||||
---
|
||||
|
||||
### 何为无Cookie模式?
|
||||
|
||||
无Cookie:特指不支持Cookie功能的终端,通俗来讲就是我们常说的 —— **前后台分离模式**
|
||||
|
||||
常规PC端鉴权方法,一般由`Cookie模式`完成,而`Cookie`有两个特性:
|
||||
常规PC端鉴权方法,一般由`Cookie模式`完成,而 Cookie 有两个特性:
|
||||
1. 可由后端控制写入
|
||||
2. 每次请求自动提交
|
||||
|
||||
这就使得我们在前端代码中,无需任何特殊操作,就能完成鉴权的全部流程(因为整个流程都是后端控制完成的)<br/>
|
||||
而在app、小程序等前后台分离场景中,一般是没有`Cookie`这一功能的,此时大多数人都会一脸懵逼,咋进行鉴权啊?
|
||||
而在app、小程序等前后台分离场景中,一般是没有 Cookie 这一功能的,此时大多数人都会一脸懵逼,咋进行鉴权啊?
|
||||
|
||||
见招拆招,其实答案很简单:
|
||||
- 不能后端控制写入了,就前端自己写入(难点在**后端如何将token传递到前端**)
|
||||
@@ -20,14 +20,14 @@
|
||||
|
||||
### 1、后端将 token 返回到前端
|
||||
|
||||
1. 首先调用 `StpUtil.login(Object loginId)` 进行登录
|
||||
1. 首先调用 `StpUtil.login(id)` 进行登录
|
||||
2. 调用 `StpUtil.getTokenInfo()` 返回当前会话的token详细参数
|
||||
- 此方法返回一个对象,其有两个关键属性:`tokenName`和`tokenValue`(`token`的名称和`token`的值)
|
||||
- 此方法返回一个对象,其有两个关键属性:`tokenName`和`tokenValue`(token 的名称和 token 的值)
|
||||
- 将此对象传递到前台,让前端人员将这两个值保存到本地
|
||||
|
||||
### 2、前端将 token 提交到后端
|
||||
1. 无论是app还是小程序,其传递方式都大同小异
|
||||
2. 那就是,将`token`塞到请求`header`里 ,格式为:`{tokenName: tokenValue}`
|
||||
2. 那就是,将 token 塞到请求`header`里 ,格式为:`{tokenName: tokenValue}`
|
||||
3. 以经典跨端框架 [uni-app](https://uniapp.dcloud.io/) 为例:
|
||||
|
||||
**方式1,简单粗暴**
|
||||
@@ -60,7 +60,7 @@ uni.setStorageSync('tokenValue', tokenValue);
|
||||
var tokenName = uni.getStorageSync('tokenName'); // 从本地缓存读取tokenName值
|
||||
var tokenValue = uni.getStorageSync('tokenValue'); // 从本地缓存读取tokenValue值
|
||||
var header = {
|
||||
"content-type": "application/x-www-form-urlencoded" // 防止后台拿不到参数
|
||||
"content-type": "application/x-www-form-urlencoded"
|
||||
};
|
||||
if (tokenName != undefined && tokenName != '') {
|
||||
header[tokenName] = tokenValue;
|
||||
@@ -76,14 +76,14 @@ uni.request({
|
||||
});
|
||||
```
|
||||
|
||||
4. 只要按照如此方法将`token`值传递到后端,`Sa-Token`就能像传统PC端一样自动读取到`token`值,进行鉴权
|
||||
4. 只要按照如此方法将`token`值传递到后端,Sa-Token 就能像传统PC端一样自动读取到 token 值,进行鉴权
|
||||
5. 你可能会有疑问,难道我每个`ajax`都要写这么一坨?岂不是麻烦死了
|
||||
- 你当然不能每个`ajax`都写这么一坨,因为这种重复代码都是要封装在一个函数里统一调用的
|
||||
- 你当然不能每个 ajax 都写这么一坨,因为这种重复性代码都是要封装在一个函数里统一调用的
|
||||
|
||||
|
||||
### 其它解决方案?
|
||||
如果你对`Cookie`非常了解,那你就会明白,所谓`Cookie`,本质上就是一个特殊的`header`参数而已 <br>
|
||||
而既然它只是一个`header`参数,我们就能手动模拟实现它,从而完成鉴权操作
|
||||
如果你对 Cookie 非常了解,那你就会明白,所谓 Cookie ,本质上就是一个特殊的`header`参数而已 <br>
|
||||
而既然它只是一个 header 参数,我们就能手动模拟实现它,从而完成鉴权操作
|
||||
|
||||
这其实是对`无Cookie模式`的另一种解决方案,有兴趣的同学可以百度了解一下,在此暂不赘述
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# [记住我] 模式
|
||||
---
|
||||
|
||||
如下图所示,一般网站的登录界面都会有一个 [ 记住我 ] 按钮,当你勾选它后,即时你关闭浏览器再次打开网站,也依然会处于登录状态,无须重复验证密码
|
||||
如图所示,一般网站的登录界面都会有一个 **`[记住我]`** 按钮,当你勾选它后,即时你关闭浏览器再次打开网站,也依然会处于登录状态,无须重复验证密码
|
||||
|
||||

|
||||
|
||||
@@ -26,8 +26,8 @@ Cookie作为浏览器提供的默认会话跟踪机制,其生命周期有两
|
||||
- 永久Cookie:有效期为一个具体的时间,在时间未到期之前,即使用户关闭了浏览器Cookie也不会消失
|
||||
|
||||
利用Cookie的此特性,我们便可以轻松实现 [记住我] 模式:
|
||||
- 勾选[记住我]按钮时:调用`StpUtil.login(10001, true)`,在浏览器写入一个`永久Cookie`储存token,此时用户即使重启浏览器token依然有效
|
||||
- 不勾选[记住我]按钮时:调用`StpUtil.login(10001, false)`,在浏览器写入一个`临时Cookie`储存token,此时用户在重启浏览器后token便会消失,导致会话失效
|
||||
- 勾选 [记住我] 按钮时:调用`StpUtil.login(10001, true)`,在浏览器写入一个`永久Cookie`储存 Token,此时用户即使重启浏览器 Token 依然有效
|
||||
- 不勾选 [记住我] 按钮时:调用`StpUtil.login(10001, false)`,在浏览器写入一个`临时Cookie`储存 Token,此时用户在重启浏览器后 Token 便会消失,导致会话失效
|
||||
|
||||
|
||||
### 前后台分离模式下如何实现[记住我]?
|
@@ -1,4 +1,4 @@
|
||||
# Token前缀
|
||||
# 自定义 Token 前缀
|
||||
|
||||
### 需求场景
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
``` java
|
||||
sa-token:
|
||||
# token前缀
|
||||
tokenPrefix: Bearer
|
||||
token-prefix: Bearer
|
||||
```
|
||||
|
||||
此时 Sa-Token 便可在读取token时裁剪掉 `Bearer`,成功获取`xxxx-xxxx-xxxx-xxxx`
|
||||
此时 Sa-Token 便可在读取 Token 时裁剪掉 `Bearer`,成功获取`xxxx-xxxx-xxxx-xxxx`
|
||||
|
||||
|
||||
### 注意点
|
||||
|
||||
1. `token前缀` 与 `token值` 之间必须有一个空格
|
||||
2. 一旦配置了`token前缀`,则前端提交token时,必须带有前缀,否则会导致框架无法读取token
|
||||
3. 由于`Cookie`中无法存储空格字符,也就意味配置token前缀后,`Cookie`鉴权方式将会失效,此时只能将token提交到`header`里进行传输
|
||||
1. Token前缀 与 Token值 之间必须有一个空格
|
||||
2. 一旦配置了 Token前缀,则前端提交token时,必须带有前缀,否则会导致框架无法读取token
|
||||
3. 由于`Cookie`中无法存储空格字符,也就意味配置token前缀后,Cookie鉴权方式将会失效,此时只能将token提交到`header`里进行传输
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# 花式token
|
||||
# 自定义 Token 风格
|
||||
|
||||
本篇介绍token生成的各种风格,以及自定义token生成策略
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
## 内置风格
|
||||
|
||||
Sa-Token默认的token生成策略是uuid风格, 其模样类似于:`623368f0-ae5e-4475-a53f-93e4225f16ae`<br>
|
||||
Sa-Token默认的token生成策略是uuid风格,其模样类似于:`623368f0-ae5e-4475-a53f-93e4225f16ae`<br>
|
||||
如果你对这种风格不太感冒,还可以将token生成设置为其他风格
|
||||
|
||||
怎么设置呢?只需要在yml配置文件里设置 `sa-token.token-style=风格类型` 即可,其有多种取值:
|
||||
@@ -56,7 +56,7 @@ public class MySaTokenAction extends SaTokenActionDefaultImpl {
|
||||
// 重写token生成策略
|
||||
@Override
|
||||
public String createToken(Object loginId, String loginType) {
|
||||
return SaTokenInsideUtil.getRandomString(60); // 随机60位字符串
|
||||
return SaFoxUtil.getRandomString(60); // 随机60位字符串
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -68,20 +68,20 @@ gfuPSwZsnUhwgz08GTCH4wOgasWtc3odP4HLwXJ7NDGOximTvT4OlW19zeLH
|
||||
|
||||
|
||||
|
||||
## 以雪花算法生成token
|
||||
在此再举一个例子,以`自定义token生成策略`的方式集成`雪花算法`来生成token
|
||||
<!-- ## 以雪花算法生成token
|
||||
在此再举一个例子,以`自定义token生成策略`的方式集成`雪花算法`来生成token -->
|
||||
|
||||
1、首先我们需要找一个合适的类库,帮助我们生成雪花算法唯一id,在此推荐 [Hutool](https://hutool.cn/docs/#/) ,在`pom.xml`里添加依赖:
|
||||
<!-- 1、首先我们需要找一个合适的类库,帮助我们生成雪花算法唯一id,在此推荐 [Hutool](https://hutool.cn/docs/#/) ,在`pom.xml`里添加依赖:
|
||||
``` xml
|
||||
<!-- Hutool 一个小而全的Java工具类库 -->
|
||||
Hutool 一个小而全的Java工具类库
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.5.4</version>
|
||||
</dependency>
|
||||
```
|
||||
``` -->
|
||||
|
||||
2、同上,我们需要新建文件`MySaTokenAction.java`,继承`SaTokenActionDefaultImpl`默认实现类, 并添加上注解`@Component`,保证此类被`springboot`扫描到
|
||||
<!-- 2、同上,我们需要新建文件`MySaTokenAction.java`,继承`SaTokenActionDefaultImpl`默认实现类, 并添加上注解`@Component`,保证此类被`springboot`扫描到
|
||||
``` java
|
||||
package com.pj.satoken;
|
||||
|
||||
@@ -100,9 +100,9 @@ public class MySaTokenAction extends SaTokenActionDefaultImpl {
|
||||
return IdUtil.getSnowflake(1, 1).nextIdStr(); // 以雪花算法生成token
|
||||
}
|
||||
}
|
||||
```
|
||||
``` -->
|
||||
|
||||
3、再次调用 `StpUtil.login(10001)`方法进行登录,观察其生成的token样式:
|
||||
<!-- 3、再次调用 `StpUtil.login(10001)`方法进行登录,观察其生成的token样式:
|
||||
``` html
|
||||
1339604338175250432
|
||||
```
|
||||
``` -->
|
Reference in New Issue
Block a user