2021-09-15 01:15:45 +08:00
|
|
|
|
# 常见问题排查
|
2021-02-09 14:39:17 +08:00
|
|
|
|
本篇整理大家在群聊里经常提问的一些问题,如有补充,欢迎提交pr
|
2020-02-06 00:52:49 +08:00
|
|
|
|
|
2021-12-25 07:35:10 +08:00
|
|
|
|
[[toc]]
|
|
|
|
|
|
2020-02-06 00:52:49 +08:00
|
|
|
|
---
|
|
|
|
|
|
2021-09-15 01:15:45 +08:00
|
|
|
|
<!-- ---------------------------- 常见报错 ----------------------------- -->
|
2021-01-31 23:28:42 +08:00
|
|
|
|
|
2021-09-15 01:15:45 +08:00
|
|
|
|
## 一、常见报错
|
2020-02-06 00:52:49 +08:00
|
|
|
|
|
2023-05-11 15:22:18 +08:00
|
|
|
|
### Q:报错:非 web 上下文无法获取 HttpServletRequest。
|
2021-01-31 23:28:42 +08:00
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
报错原因解析:
|
2020-02-06 00:52:49 +08:00
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
Sa-Token 的部分 API 只能在 Web 上下文中才能调用,例如:`StpUtil.getLoginId()` 获取当前用户Id,这个方法第一步需要先从前端提交的参数里获取 token 值,
|
|
|
|
|
当你在 main 方法里调用这个 API 时,由于 main 方法本质上不是一个 Controller 请求,所以框架无法完成 *“从前端提交的参数里获取 token 值”* 这一步骤,框架就只能抛出异常。
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
按照此标准,Sa-Token 的 API 可粗浅的分为两大类:
|
|
|
|
|
- 必须在 Web 上下文中才能调用的 API,例如:`StpUtil.getLoginId()`、`StpUtil.getTokenValue()` 等等。
|
|
|
|
|
- 无需 Web 上下文也能调用的 API,例如:`StpUtil.getLoginType()`、`SaManager.getConfig()` 等等。
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
此处无法逐一列出到底哪些 API 属于 *“必须依赖 Web 上下文的 API”*,因为太多了,你只需要记住关键的一点:
|
|
|
|
|
**当一个 API 执行的代码需要先从前端请求中获取一些数据时,这个 API 就属于 *“必须依赖 Web 上下文的 API”*。**
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
如果你的代码报这个错,说明你在不是 Web 上下文中的地方,调用了 *“必须依赖 Web 上下文的 API”*,请排查:
|
|
|
|
|
|
|
|
|
|
1. 是否在 main 方法中调用了 *“必须依赖 Web 上下文的 API”*。
|
|
|
|
|
2. 是否在带有 `@Async` 注解的方法中调用了 *“必须依赖 Web 上下文的 API”*。
|
|
|
|
|
3. 是否在一些丢失 web 上下文的子线程中调用了 *“必须依赖 Web 上下文的 API”*,例如 `MyBatis-Plus` 的 `insertFill` 自动填充。
|
|
|
|
|
4. 是否在一些非 Http 协议的 RPC 框架中(例如 Dubbo)调用了 *“必须依赖 Web 上下文的 API”*。
|
|
|
|
|
5. 是否在 SpringBoot 启动初始化的方法中调用了 *“必须依赖 Web 上下文的 API”*,例如 `@PostConstruct` 修饰的方法。
|
|
|
|
|
6. 是否在定时任务中调用了 *“必须依赖 Web 上下文的 API”*。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Q:报错:未能获取有效的上下文处理器。
|
|
|
|
|
|
|
|
|
|
报错原因解析:
|
|
|
|
|
|
|
|
|
|
在 sa-token-core 核心包中,Sa-Token 底层不能确认最终运行的 web 容器,所以抽象了 `SaTokenContext` 接口,对接不同容器时需要注入不同的实现,
|
|
|
|
|
通常这个注入工作都是框架自动完成的,你只需要按照文档开始部分集成相应的依赖即可。例如:
|
|
|
|
|
|
|
|
|
|
- 你要在 Springboot2.x 中使用 Sa-Token,就引入:`sa-token-spring-boot-starter`。
|
|
|
|
|
- 你要在 Springboot3.x 中使用 Sa-Token,就引入:`sa-token-spring-boot3-starter`。
|
|
|
|
|
- 你要在基于 webflux 架构的网关中使用 Sa-Token,就引入:`sa-token-reactor-spring-boot-starter`。
|
|
|
|
|
- 你要在 Solon 中使用 Sa-Token,就引入:`sa-token-solon-plugin`。
|
|
|
|
|
- 等等等等……
|
|
|
|
|
|
|
|
|
|
如果你的代码报 *“未能获取有效的上下文处理器”* 这个错,大概率是因为你没有正确引入所需的包,导致框架没有注入正确的 `SaTokenContext` 上下文实现,请排查:
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
|
|
|
|
1. 如果你的项目是微服务项目,请直接参考:[微服务-依赖引入说明](/micro/import-intro),如果是单体项目,请往下看:
|
2023-03-26 11:30:17 +08:00
|
|
|
|
2. 请判断你的项目是 SpringMVC 环境还是 WebFlux 环境:
|
2021-09-15 01:15:45 +08:00
|
|
|
|
- 如果是 SpringMVC 环境就引入 `sa-token-spring-boot-starter` 依赖,参考:[在SpringBoot环境集成](/start/example)
|
|
|
|
|
- 如果是 WebFlux 环境就引入 `sa-token-reactor-spring-boot-starter` 依赖,参考:[在WebFlux环境集成](/start/webflux-example)
|
2023-03-26 11:30:17 +08:00
|
|
|
|
3. 如果你还无法分辨你是哪个环境,就看你的 pom.xml 依赖:
|
|
|
|
|
- 如果引入了`spring-boot-starter-web`就是 SpringMVC 环境。
|
|
|
|
|
- 如果引入了 `spring-boot-starter-webflux` 就是WebFlux环境。
|
|
|
|
|
- 什么?你说你两个都引入了?那你的项目能启动成功吗?
|
|
|
|
|
4. 如果是 WebFlux 环境而且正确引入了依赖,依然报错,**请检查是否注册了 SaReactorFilter 全局过滤器,在 WebFlux 下这一步是必须的**,具体还是请参考上面的 [ 在WebFlux环境集成 ] 章节。
|
|
|
|
|
5. 需要仔细注意,如果你使用的是 Springboot3.x 版本,就不要错误的引入 `sa-token-spring-boot-starter`,需要引入的是 `sa-token-spring-boot3-starter`,不然就会导致框架报错。
|
|
|
|
|
6. 如果以上步骤排除无误后依然报错,请直接提 issue 或者加入QQ群求助。
|
2022-08-17 11:00:06 +08:00
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:报错:NotLoginException:xxx
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
这个错是说明调用接口的人没有通过登录校验,请注意:**通常情况下,异常提示语已经描述清楚了没有通过校验的具体原因:**
|
2022-08-31 17:07:06 +08:00
|
|
|
|
|
|
|
|
|
**如果是:未能读取到有效Token**
|
|
|
|
|
- 可能1:前端没有提交 Token(最好从前端f12控制台看看请求参数里有 token 吗)。
|
|
|
|
|
- 可能2:前端提交了 Token,但是参数名不对。默认参数名是 `satoken`,可通过配置文件 `sa-token.token-name: satoken` 来更改。
|
2022-09-04 04:03:03 +08:00
|
|
|
|
- 可能3:前端提交了 Token,但是你配置了框架不读取,比如说你配置了 `is-read-header=false`(关闭header读取),此时你再从 header 里提交token,框架就无法读取到。
|
2022-08-31 17:07:06 +08:00
|
|
|
|
- 可能4:前端提交了 Token,但是 Token前缀 不对,可参考:[自定义 Token 前缀](/up/token-prefix)
|
2023-04-10 08:13:23 +08:00
|
|
|
|
- 可能5:你的项目属于前后端分离架构,此时浏览器默认不自动提交 Cookie,参考:[前后端分离](/up/not-cookie)
|
|
|
|
|
- 可能6:你使用了 Nginx 反向代理,而且配置了 自定义Token名称,而且自定义的名称还带有下划线(比如 shop_token),而且还是你的项目还是从 Header头提交Token的,此时 Nginx 默认会吞掉你的下划线参数,可参考:[nginx做转发时,带下划线的header参数丢失](https://blog.csdn.net/zfw_666666/article/details/124420828)
|
2022-08-31 17:07:06 +08:00
|
|
|
|
|
|
|
|
|
**如果是:Token无效:6ad93254-b286-4ec9-9997-4430b0341ca0**
|
2022-08-31 18:29:17 +08:00
|
|
|
|
- 可能1:前端提交的 token 是乱填的,或者从别的项目拷过来的,或者多个项目一起开发时彼此的 Token 串项目了。
|
2022-08-31 17:07:06 +08:00
|
|
|
|
- 可能2:前端提交的 token 已过期(timeout超时了)。
|
|
|
|
|
- 可能3:在不集成 Redis 的情况下:颁发 token 后,项目重启了,导致 token 无效。
|
|
|
|
|
- 可能4:在集成 Redis 的情况下:颁发 token 后,Redis重启了,导致 token 无效。
|
|
|
|
|
- 可能5:你提交的 token 和框架读取到的 token 不一致:
|
2022-09-04 04:03:03 +08:00
|
|
|
|
- 可能5.1:比如说你配置了`is-read-header=false`(关闭header读取),然后你从header提交`token-A`,而框架从Cookie里读取`token-B`,导致鉴权不通过(框架读取顺序为`body->header->cookie`)
|
2022-08-31 17:07:06 +08:00
|
|
|
|
- 可能5.2:比如说你配置了`token-name=x-token`(自定义token名称),此时你从header提交:`satoken:token-A`(参数名没对上),然后框架从header里读取不到你提交的token,转而继续从Cookie读取到了`token-B`。
|
|
|
|
|
- 可能6:在集成 jwt 插件的情况下:
|
|
|
|
|
- 如果使用的是 Simple 模式:情况和不集成jwt一样。
|
|
|
|
|
- 如果使用的是 Mixin 和 Stateless 模式:查看这个 token 颁发后是否更改了 `jwtSecretKey` 配置项。
|
|
|
|
|
- 可能7:同一账号登录数量超过12个,导致最先登录的被强制注销掉,这个值可以通过 `maxLoginCount` 来配置,默认值12,-1代表不做限制。
|
|
|
|
|
- 可能8:在配置了 `is-concurrent=true, is-share=true`的情况下,你和别人共同登录了同一账号,此时对方注销了登录,由于你们使用的是同一个token,导致你这边的会话也失效了。
|
2022-08-31 18:29:17 +08:00
|
|
|
|
- 可能9:可能是多账号鉴权的关系,在多账号模式下,如果是 `StpUserUtil.login()` 颁发的token,你从 `StpUtil.checkLogin()` 进行校验,永远都是无效token,因为账号体系没对上。
|
2022-08-31 17:07:06 +08:00
|
|
|
|
|
|
|
|
|
**如果是:Token已过期:6ad93254-b286-4ec9-9997-4430b0341ca0**
|
2022-08-31 23:17:30 +08:00
|
|
|
|
- 可能1:前端提交的 token 临时过期(activity-timeout超时了,比如配置了 activity-timeout=120,但是超过了120秒没有访问接口)。
|
2022-08-31 17:07:06 +08:00
|
|
|
|
- 可能2:集成jwt,而且使用的是 Mixin 或 Stateless 模式,而且token过期了(timeout超时了)。
|
|
|
|
|
|
|
|
|
|
**如果是:Token已被顶下线:6ad93254-b286-4ec9-9997-4430b0341ca0**
|
|
|
|
|
- 可能1:在项目配置了 `is-concurrent=false` 的前提下,这个账号又被别人登录了,导致旧登录被挤了下去。
|
|
|
|
|
- 可能2:这个账号被 `StpUtil.replaced(loginId, device)` 方法强制顶下线了。
|
|
|
|
|
|
|
|
|
|
**如果是:Token已被踢下线:6ad93254-b286-4ec9-9997-4430b0341ca0**
|
|
|
|
|
- 可能1:这个账号被 `StpUtil.kickout(loginId)` 方法强制踢下线了。
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:加了注解进行鉴权认证,不生效?
|
2022-08-21 10:15:45 +08:00
|
|
|
|
1. 注解鉴权功能默认关闭,两种方式任选其一进行打开:注册注解拦截器、集成AOP模块,参考:[注解式鉴权](/use/at-check)
|
|
|
|
|
2. 在Spring环境中, 如果同时配置了`WebMvcConfigurer`和`WebMvcConfigurationSupport`时, 也会导致拦截器失效.
|
2022-08-22 16:30:18 +08:00
|
|
|
|
- **常见场景**: 很多项目中会在`WebMvcConfigurationSupport`中配置`addResourceHandlers`方法开放Swagger等相关静态资源映射, 同时基于Sa-Token添加了`WebMvcConfigurer`配置`addInterceptors`方法注册注解拦截器, 这样会导致注解拦截器失效.
|
|
|
|
|
- **解决方案**: `WebMvcConfigurer`和`WebMvcConfigurationSupport`只选一个配置, 建议统一通过实现`WebMvcConfigurer`接口进行配置.
|
|
|
|
|
3. 如果以上步骤处理后仍然没有效果,加群说明一下复现步骤
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
|
|
|
|
|
2022-11-16 21:13:02 +08:00
|
|
|
|
|
2022-09-24 01:33:40 +08:00
|
|
|
|
### Q:我加了拦截器鉴权,但是好像没有什么效果,请求没有被拦截住?
|
|
|
|
|
- 可能1:这个拦截器可能没有注册成功。
|
|
|
|
|
- 可能2:你访问的请求没有进入这个拦截器。
|
|
|
|
|
|
|
|
|
|
尝试按照下面的代码测试一下看看:
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
// 注册拦截器
|
|
|
|
|
@Configuration
|
|
|
|
|
public class SaTokenConfigure implements WebMvcConfigurer {
|
|
|
|
|
@Override
|
|
|
|
|
public void addInterceptors(InterceptorRegistry registry) {
|
|
|
|
|
System.out.println("--------- flag 1");
|
|
|
|
|
registry.addInterceptor(new SaInterceptor(handle -> {
|
2022-11-16 21:13:02 +08:00
|
|
|
|
System.out.println("--------- flag 2,请求进入了拦截器,访问的 path 是:" + SaHolder.getRequest().getRequestPath());
|
2022-09-24 01:33:40 +08:00
|
|
|
|
StpUtil.checkLogin(); // 登录校验,只有会话登录后才能通过这句代码
|
|
|
|
|
}))
|
|
|
|
|
.addPathPatterns("/user/**")
|
|
|
|
|
.excludePathPatterns("/user/doLogin");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
在启动时 `flag 1` 被打印出来,才证明拦截器注册成功了,在访问请求时 `flag 2` 被打印出来,才证明请求进入了拦截器。
|
|
|
|
|
|
|
|
|
|
如果拦截器没有注册成功,则:
|
2022-11-16 21:13:02 +08:00
|
|
|
|
<!-- - 可能1:SpringBoot 版本较高(`>= 2.6.0`),请尝试在启动类加上 `@EnableWebMvc` 注解再重新启动。 -->
|
|
|
|
|
- 可能1:`SaTokenConfigure` 配置类不在启动类的同包或者子包下,导致没有被 SpringBoot 扫描到。
|
|
|
|
|
- 可能2:你的项目启动类上加了 `@ComponentScan("com.xxx")` 注解,导致包扫描范围不正确,请将此注解删除或移动到其它配置类上。
|
|
|
|
|
- 可能3:项目属于 Maven 多模块项目,`SaTokenConfigure` 和启动类没有在一个模块,且启动类模块没有引入配置类的模块,导致加载不到。
|
2022-09-24 01:33:40 +08:00
|
|
|
|
|
|
|
|
|
如果拦截器已经注册成功,但请求没有进入拦截器:
|
2022-11-16 21:13:02 +08:00
|
|
|
|
- 可能1:你访问的 path,没有被 `.addPathPatterns("/user/**")` 拦截住,或者被 `.excludePathPatterns("/xxx/xx")` 排除掉了。
|
|
|
|
|
- 可能2:你访问的是另一个项目,请把当前项目停掉,看看你的请求还能不能访问成功。
|
|
|
|
|
|
|
|
|
|
如果请求进入拦截器也成功了,那可能是:
|
|
|
|
|
- 可能1:前端访问时提交了会话 Token,且这个 Token 是有效的,通过了拦截器的代码校验。
|
|
|
|
|
- 可能2:你访问的 path,和你预期不符,仔细观察一下打印出来的 path 信息,和你的预期相符吗。
|
2022-09-24 01:33:40 +08:00
|
|
|
|
|
|
|
|
|
注:以上的排查步骤,对过滤器不生效的情形一样适用。
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:我使用拦截器鉴权时,明明排除了某个路径却仍然被拦截了?
|
|
|
|
|
- 可能1:你的项目可能是跨域了,先把跨域问题解决掉,参考:[解决跨域问题](/fun/cors-filter)
|
|
|
|
|
- 可能2:你访问的接口可能是404了,SpringBoot环境下如果访问接口404后,会被转发到`/error`,然后被再次拦截。请确保你访问的 path 有对应的 Controller 承接!
|
2022-11-16 21:13:02 +08:00
|
|
|
|
- 可能3:可能拦截器这里并没有拦截,但是又被其他地方拦截了。请先把这个拦截器给注释掉,看看还会不会拦截,如果依然拦截,那说明不是这个拦截器的锅,请仔细查看一下控制台抛出的堆栈信息,定位一下到底是哪行代码拦截住这个请求的。
|
|
|
|
|
- 可能4:后端拦截的 path 未必是你前端访问的这个path(特别是经过网关转发后的path可能会有变化),建议先打印一下 path 信息,看看和你预想的是否一致,再做分析。
|
2022-09-01 18:14:48 +08:00
|
|
|
|
``` java
|
2022-11-16 21:13:02 +08:00
|
|
|
|
@Override
|
|
|
|
|
public void addInterceptors(InterceptorRegistry registry) {
|
|
|
|
|
registry.addInterceptor(new SaInterceptor(handle -> {
|
|
|
|
|
try {
|
|
|
|
|
System.out.println("-------- 前端访问path:" + SaHolder.getRequest().getRequestPath());
|
|
|
|
|
StpUtil.checkLogin();
|
|
|
|
|
System.out.println("-------- 此 path 校验成功:" + SaHolder.getRequest().getRequestPath());
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.out.println("-------- 此 path 校验失败:" + SaHolder.getRequest().getRequestPath());
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
})).addPathPatterns("/**");
|
|
|
|
|
}
|
2022-10-28 18:09:44 +08:00
|
|
|
|
```
|
2022-11-16 21:13:02 +08:00
|
|
|
|
- 可能5:可能你只提交了一个请求,但是浏览器自动帮你提交了其它请求,举个例子:首次访问网站时,浏览器一般会自动提交 `/favicon.ico`,所以**你需要找出是哪个path被拦截了**,怎么找呢?用【可能4】的代码来测试找。
|
|
|
|
|
- 可能6:你的项目配置了 `context-path` 上下文地址,比如 `server.servlet.context-path=/shop`,注意这个地址是不需要加在拦截器上的:
|
2022-10-28 18:09:44 +08:00
|
|
|
|
``` java
|
|
|
|
|
// 这是错误示例,不需要把 context-path 上下文参数写在下面的 excludePathPatterns 地址上。
|
|
|
|
|
registry.addInterceptor(new SaInterceptor(hadnle -> StpUtil.checkLogin()))
|
|
|
|
|
.addPathPatterns("/**").excludePathPatterns("/shop/user/login");
|
|
|
|
|
// 这是正确示例,无论你的 context-path 上下文配置了什么样的值,下面的 excludePathPatterns 地址都不需要写上它
|
|
|
|
|
registry.addInterceptor(new SaInterceptor(hadnle -> StpUtil.checkLogin()))
|
|
|
|
|
.addPathPatterns("/**").excludePathPatterns("/user/login");
|
|
|
|
|
```
|
2022-11-16 21:13:02 +08:00
|
|
|
|
- 可能7:你写了多个匹配规则,请求越过了第一个规则,但又被其它规则拦下来了,例如以下代码:
|
2022-10-28 18:09:44 +08:00
|
|
|
|
``` java
|
|
|
|
|
// 以下代码,当你未登录访问 `/user/doLogin` 时,会被第1条规则越过,然后被第2条拦下,校验登录,然后抛出异常:`NotLoginException:xxx`
|
2022-09-01 18:14:48 +08:00
|
|
|
|
registry.addInterceptor(new SaInterceptor(handler -> {
|
|
|
|
|
SaRouter.match("/**").notMatch("/user/doLogin").check(r -> StpUtil.checkLogin()); // 第1个规则
|
|
|
|
|
SaRouter.match("/**").notMatch("/article/getList").check(r -> StpUtil.checkLogin()); // 第2个规则
|
|
|
|
|
SaRouter.match("/**").notMatch("/goods/getList").check(r -> StpUtil.checkLogin()); // 第3个规则
|
|
|
|
|
})).addPathPatterns("/**");
|
|
|
|
|
```
|
2022-11-16 21:13:02 +08:00
|
|
|
|
- 可能8:你自定义的封装方法,并没有按照你的预想情况执行:
|
2022-10-28 18:09:44 +08:00
|
|
|
|
``` java
|
|
|
|
|
public void addInterceptors(InterceptorRegistry registry) {
|
|
|
|
|
registry.addInterceptor(new SaInterceptor(handle -> {
|
|
|
|
|
// 调用自定义的 excludePaths() 方法获取数据排除鉴权
|
|
|
|
|
SaRouter.match("/**").notMatch(excludePaths()).check(r -> StpUtil.checkLogin());
|
|
|
|
|
})).addPathPatterns("/**");
|
|
|
|
|
}
|
|
|
|
|
// 自定义查询排查鉴权的地址方法
|
|
|
|
|
public static List<String> excludePaths() {
|
|
|
|
|
List<String> list = ... // 从数据源查询...;
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
如上方法, `excludePaths()` 可能并不会像你预想的一样正确执行返回相应的值,请在 `.notMatch()` 处 `一律先硬编码写固定死值来测试`,这时就有两种情况:
|
|
|
|
|
- 情况1:写固定死值时,代码能正常执行了,那说明你自定义的 `excludePaths()` 方法有问题,执行结果不正确。
|
|
|
|
|
- 情况2:写固定也不行,那说明不是 `excludePaths()` 的问题,那再从其它地方开始排查。
|
|
|
|
|
|
2021-01-31 23:28:42 +08:00
|
|
|
|
|
2020-04-21 23:34:55 +08:00
|
|
|
|
|
2022-10-21 17:00:48 +08:00
|
|
|
|
### Q:我在配置文件中加了一些关于 Sa-Token 的配置,但是没有生效。
|
|
|
|
|
首先,有没有生效的最佳判断方式是,在main方法中加一个打印,看看打印出来的和你配置文件的一致吗:
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
@SpringBootApplication
|
|
|
|
|
public class SaTokenApplication {
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
SpringApplication.run(SaTokenApplication.class, args);
|
|
|
|
|
System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
如果不一致,请排查:
|
|
|
|
|
- 可能1:项目中还存在代码配置,而代码配置会覆盖 `application.yml` 中配置,详细参考:[框架配置](/use/config)。
|
|
|
|
|
- 可能2:你的配置文件名字错误,SpringBoot 项目正常情况下配置文件名称应该是:`application.yml` 或 `application.properties`。
|
2022-10-23 17:32:04 +08:00
|
|
|
|
- 可能3:可能是你的配置前缀不对,或者配置缩进不对:
|
|
|
|
|
``` yaml
|
|
|
|
|
# 错误示例,多加了 spring 前缀
|
|
|
|
|
spring:
|
|
|
|
|
sa-token:
|
|
|
|
|
token-name: xxx-token
|
|
|
|
|
# 错误示例,缩进不对
|
|
|
|
|
sa-token:
|
|
|
|
|
token-name: xxx-token
|
|
|
|
|
# 正确的应该是以 sa-token 开头
|
|
|
|
|
sa-token:
|
|
|
|
|
token-name: xxx-token
|
|
|
|
|
```
|
2022-10-21 17:00:48 +08:00
|
|
|
|
|
|
|
|
|
|
2022-10-23 18:52:30 +08:00
|
|
|
|
### Q:我自定义了组件,但是好像没有生效?
|
2023-03-26 11:30:17 +08:00
|
|
|
|
1、可能组件没有注入成功,排查方法为在 main 里打印这个组件,是否为自定义的class限定名:
|
2022-10-23 18:52:30 +08:00
|
|
|
|
``` java
|
|
|
|
|
@SpringBootApplication
|
|
|
|
|
public class SaTokenApplication {
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
SpringApplication.run(SaTokenApplication.class, args);
|
|
|
|
|
System.out.println(SaManager.getStpInterface()); // 打印全局的 StpInterface 实现类
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
如果打印出的是你的自定义实现类,则证明注入成功,如果不是,则证明没有注入成功,请排查:
|
|
|
|
|
- 自定义的组件实现类上是否加上了 `@Component` 注解,只有加上这个注解,组件才会被 Spring 自动实例化并注入。
|
|
|
|
|
- 自定义的组件实现类是否在启动类的同目录或者子目录上,如果不在则无法被 springboot 启动时扫描,扫描不到也就无法注入。
|
|
|
|
|
- 启动类上是否加了 `@ComponentScan` 注解,导致包扫描范围不正确,请将此注解删除或移动到其它配置类上。
|
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
2、这个组件注入成功了,但是还没到执行时机,比如 `StpInterface` 组件,只有在鉴权时才会触发,如果你的代码仅仅是登录校验,就不会执行到这个组件。
|
2022-10-23 18:52:30 +08:00
|
|
|
|
|
|
|
|
|
|
2022-11-16 21:13:02 +08:00
|
|
|
|
### Q:集成 Redis 后,明明 Redis 中有值,却还是提示无效Token?
|
|
|
|
|
|
|
|
|
|
根据以往的处理经验,发生这种情况 90% 的概率是因为你找错了Redis,即:代码连接的Redis和你用管理工具看到的Redis并不是同一个。
|
|
|
|
|
|
|
|
|
|
你可能会问:我看配置文件明明是同一个啊?
|
|
|
|
|
|
|
|
|
|
我的回答是:别光看配置文件,不一定准确,在启动时直接执行 `SaManager.getSaTokenDao().set("name", "value", 100000);`,
|
|
|
|
|
随便写入一个值,看看能不能根据你的预期写进这个Redis,如果能的话才能证明`代码连接的Reids` 和`你用管理工具看到的Redis` 是同一个,再进行下一步排查。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Q:报错:无效Same-Token:xxxxxxxxxxx
|
|
|
|
|
与之类似的的报错还有:
|
|
|
|
|
- SSO模式二时,报错:无效ticket:xxxxxxxxxx
|
|
|
|
|
- OAuth2模块跨多个项目搭建Server时:报错无效 Access-Token:xxxxxx
|
|
|
|
|
- 微服务做分布式 Session 认证时,报错:无效 Token:xxxxxxxxx
|
|
|
|
|
- 等等等等....
|
|
|
|
|
|
|
|
|
|
这些功能有个统一的特点,就是需要多个项目连接同一个 Redis 才能搭建成功,如果连接的不是同一个 Redis,就会导致 Token / ticket 无法互相认证。
|
|
|
|
|
|
|
|
|
|
你可能会问:我看配置文件明明就是连接的同一个 Redis 啊?
|
|
|
|
|
|
|
|
|
|
别急,和上一个问题一样,**不要凭借肉眼检查下定论**,在你的两个服务之间,分别使用以下代码测试一下:
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
@SpringBootApplication
|
2022-11-16 23:22:47 +08:00
|
|
|
|
public class SaTokenApplication {
|
2022-11-16 21:13:02 +08:00
|
|
|
|
public static void main(String[] args) {
|
2022-11-16 23:22:47 +08:00
|
|
|
|
SpringApplication.run(SaTokenApplication.class, args);
|
2022-11-16 21:13:02 +08:00
|
|
|
|
// 写值测试:注意一定要用下列方法测试,不要用自己封装的 RedisUtil 之类的测试
|
|
|
|
|
SaManager.getSaTokenDao().set("name", "value", 100000);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
如果都能根据你的预期写进同一个 Redis,那才能证明两个服务确实连接的是同一个 Redis。
|
|
|
|
|
|
|
|
|
|
实际上,在交流群中提问这些问题的同学,90%的经过以上测试以后,都会发现两者连接的不是同一个 Reids,原因大多是:Redis配置没有生效、使用了 Alone-Redis 之类的……
|
|
|
|
|
|
|
|
|
|
如果你是剩下的 10%,那么继续排查:两边的 sa-token 配置是否完全一致,比如 token-name 配置不一致,也会导致数据无法相互认证。最好是把所有 sa-token 相关的配置都复制过去,试验一下看看。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-10-23 18:52:30 +08:00
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:有时候我不加 Token 也可以通过鉴权,请问是怎么回事?
|
2022-10-21 17:00:48 +08:00
|
|
|
|
- 可能1:你访问的这个接口,根本就没有鉴权的代码,所以可以安全的访问通过。
|
|
|
|
|
- 可能2:可能是 Cookie 帮你自动提交了 Token,在浏览器或 Postman 中会自动维护Cookie模式,如不需要可以在配置文件:`is-read-cookie: false`,然后重启项目再测试一下。
|
2021-02-09 14:39:17 +08:00
|
|
|
|
|
2021-11-05 18:55:14 +08:00
|
|
|
|
|
2022-09-24 01:33:40 +08:00
|
|
|
|
### Q:一个 User 对象存进 Session 后,再取出来时报错:无法从 User 类型转换成 User 类型?
|
2022-10-21 17:00:48 +08:00
|
|
|
|
- 可能1:你的 User 类中途换了包名,导致存进去时和取出来时对不上,无法成功创建实例。
|
|
|
|
|
- 可能2:你打开了代码热刷新模式,先存进去的对象,热刷新后再取出,会报错,关闭热刷新即可解决。
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
|
|
|
|
|
2022-10-23 17:32:04 +08:00
|
|
|
|
### Q:在 SaServletFilter 中调用 SpringMVCUtil.getRequest() 报错:非Web上下文无法获取Request?
|
|
|
|
|
|
|
|
|
|
- 可能1:项目中有配置类继承了: `extends WebMvcConfigurationSupport`。
|
|
|
|
|
- 可能2:项目中有配置类添加了注解: `@EnableWebMvc`。
|
|
|
|
|
|
|
|
|
|
解决方案:不要加 `@EnableWebMvc`,不要 `extends WebMvcConfigurationSupport`,要 `implements WebMvcConfigurer`
|
|
|
|
|
|
|
|
|
|
如果不是以上原因,可以加群提供复现demo。
|
|
|
|
|
|
|
|
|
|
<!-- 目前能复现此问题的情况是:在项目中有配置类继承 `WebMvcConfigurationSupport` 时,再从 `SaServletFilter` 中调用
|
|
|
|
|
`SpringMVCUtil.getRequest()` 就会报错:`非Web上下文无法获取Request`。
|
|
|
|
|
|
|
|
|
|
解决方案是将 `extends WebMvcConfigurationSupport` 改为 `implements WebMvcConfigurer`。 -->
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:我配置了 active-timeout 值,但是当我每次续签时 Redis 中的 ttl 并没有更新,是不是 bug 了?
|
2021-09-30 14:03:30 +08:00
|
|
|
|
不更新是正常现象,`active-timeout`不是根据 ttl 计算的,是根据value值计算的,value 记录的是该 Token 最后访问系统的时间戳,
|
2022-09-24 01:33:40 +08:00
|
|
|
|
每次验签时用:当前时间 - 时间戳 > active-timeout,来判断这个 Token 是否已经超时。
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:整合 Redis 时先选择了默认jdk序列化,后又改成 jackson 序列化,程序开始报错,SerializationException?
|
2022-09-24 01:33:40 +08:00
|
|
|
|
两者的序列化算法不一致导致的反序列化失败,如果要更改序列化方式,则需要先将 Redis 中历史数据清除,再做更新。
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
|
|
|
|
|
2022-09-25 12:07:44 +08:00
|
|
|
|
### Q:调用 `StpUtil.getExtra("name")` 报错:`this api is disabled`。
|
|
|
|
|
`StpUtil.getExtra(key)` 是给 sa-token-jwt 插件提供的,不集成这个插件就不能调用这个API,如果是普通模式需要存储自定义参数,请在 SaSession 上存储
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
// 在登录时缓存参数
|
|
|
|
|
StpUtil.getSession().set("name", "zhangsan");
|
|
|
|
|
|
|
|
|
|
// 然后我们就可以在任意处获取这个参数
|
|
|
|
|
String name = StpUtil.getSession().getString("name");
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:我加了 Sa-Token 的全局过滤器,浏览器报错跨域了怎么办?
|
2021-09-15 01:15:45 +08:00
|
|
|
|
参考:[https://blog.csdn.net/shengzhang_/article/details/119928794](https://blog.csdn.net/shengzhang_/article/details/119928794)
|
|
|
|
|
|
|
|
|
|
|
2023-03-27 17:20:49 +08:00
|
|
|
|
### Q:前后端分离项目中,前端使用 vue,如果不打开 porxy 代理的话,调用 Sa-Token 登录不会将 token 自动注入到 Cookie 中,是因为跨域么?
|
|
|
|
|
是。
|
|
|
|
|
|
|
|
|
|
参考:[前后端分离](/up/not-cookie)
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:集成redis后对象模型序列化异常
|
2022-07-28 13:09:37 +08:00
|
|
|
|
假设执行如下代码:
|
|
|
|
|
``` java
|
|
|
|
|
@Data
|
|
|
|
|
public class User implements Serializable {
|
|
|
|
|
private Long userId;
|
|
|
|
|
private String username;
|
|
|
|
|
private String password;
|
|
|
|
|
}
|
2023-03-26 11:30:17 +08:00
|
|
|
|
```
|
2022-07-28 13:09:37 +08:00
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
``` java
|
2022-07-28 13:09:37 +08:00
|
|
|
|
User user = new User();
|
|
|
|
|
user.setUserId(10000L);
|
|
|
|
|
user.setUsername("oneName");
|
|
|
|
|
user.setPassword("onePass");
|
|
|
|
|
StpUtil.getSession().set("userObjKey", user); // 这里报错
|
|
|
|
|
```
|
|
|
|
|
报错信息如下:
|
|
|
|
|
```
|
|
|
|
|
SerializationException: Could not read JSON:
|
|
|
|
|
Cannot deserialize value of type `java.lang.Long` from Array value (token `JsonToken.START_ARRAY`)
|
|
|
|
|
```
|
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
Springboot 集成 Sa-Token Redis 后, 一旦 Springboot 切换版本就有可能出现此问题
|
2022-07-28 13:09:37 +08:00
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
原因是 Redis 里面有之前的 Sa-Token 会话数据, 清空 Redis 即可。
|
2022-07-28 13:09:37 +08:00
|
|
|
|
|
|
|
|
|
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
2022-10-28 18:09:44 +08:00
|
|
|
|
### Q:我实现了 StpInterface 接口,但是在登录时没有进入我的实现类代码?
|
|
|
|
|
不进入是正常现象, StpInterface 是鉴权接口,在执行鉴权代码时才会进入 StpInterface 实现类,登录认证时不会进入。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Q:启动时报错,找不到 xx 类 xx 方法:
|
|
|
|
|
``` java
|
|
|
|
|
Caused by: java.lang.ClassNotFoundException: cn.dev33.satoken.same.SaSameTemplate
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
一般找不到类,或者找不到方法,都是版本冲突了,使用 Sa-Token 时一定要注意**版本对齐**,意思是所有和 Sa-Token 相关的依赖都需要版本一致。
|
|
|
|
|
|
|
|
|
|
比如说你如果一个依赖是 1.32.0,一个是 1.31.0,就会造成无法启动:
|
|
|
|
|
|
|
|
|
|
``` xml
|
|
|
|
|
<!-- 如下样例:一个是 `1.32.0`,一个是 `1.31.0`, 版本没对齐,就会造成项目无法启动 -->
|
|
|
|
|
<dependency>
|
|
|
|
|
<groupId>cn.dev33</groupId>
|
|
|
|
|
<artifactId>sa-token-spring-boot-starter</artifactId>
|
|
|
|
|
<version>1.32.0</version>
|
|
|
|
|
</dependency>
|
|
|
|
|
<dependency>
|
|
|
|
|
<groupId>cn.dev33</groupId>
|
|
|
|
|
<artifactId>sa-token-core</artifactId>
|
|
|
|
|
<version>1.31.0</version>
|
|
|
|
|
</dependency>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
请仔细排查你的 pom.xml 文件,是否有 Sa-Token 依赖没对齐,**请不要肉眼检查,用全局搜索 "sa-token" 关键词来找**,如果是多模块或者微服务项目,就整个项目搜索。
|
|
|
|
|
|
|
|
|
|
|
2023-04-28 00:19:36 +08:00
|
|
|
|
### Q:在多账号模式的注解鉴权时,报错:未能获取对应StpLogic,type=xxx
|
|
|
|
|
|
|
|
|
|
报这个错说明对应 type 的 StpLogic 尚未初始化到全局 StpLogicMap 中,一般会有两种原因造成这种情况:
|
|
|
|
|
1. 注解里的 loginType 拼写错误,请改正 (建议使用常量)。
|
|
|
|
|
2. 自定义 StpUtil 尚未初始化(静态类中的属性至少一次调用后才会初始化),解决方法两种:
|
|
|
|
|
- (1) 从main方法里调用一次
|
|
|
|
|
- (2) 在自定义StpUtil类加上类似 @Component 的注解让容器启动时扫描到自动初始化
|
|
|
|
|
|
|
|
|
|
|
2023-05-03 05:09:15 +08:00
|
|
|
|
### Q:使用拦截器鉴权,访问一个不存在的 path 时,springboot 会自动在控制台打印一下异常。
|
|
|
|
|
可尝试添加以下配置解决:
|
|
|
|
|
``` properties
|
|
|
|
|
spring.resources.add-mappings=false
|
|
|
|
|
spring.mvc.throw-exception-if-no-handler-found=true
|
|
|
|
|
```
|
2023-04-28 00:19:36 +08:00
|
|
|
|
|
2022-10-28 18:09:44 +08:00
|
|
|
|
|
|
|
|
|
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ---------------------------- 常见疑问 ----------------------------- -->
|
|
|
|
|
|
|
|
|
|
## 二、常见疑问
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:登录方法需要我自己实现吗?
|
2021-09-15 01:15:45 +08:00
|
|
|
|
是的,不同于`shiro`等框架,`Sa-Token`不会在登录流程中强插一脚,开发者比对完用户的账号和密码之后,只需要调用`StpUtil.login(id)`通知一下框架即可
|
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
``` java
|
|
|
|
|
// 会话登录接口
|
|
|
|
|
@RequestMapping("doLogin")
|
|
|
|
|
public SaResult doLogin(String name, String pwd) {
|
|
|
|
|
// 第一步:比对前端提交的账号名称、密码
|
|
|
|
|
if("zhang".equals(name) && "123456".equals(pwd)) {
|
|
|
|
|
|
|
|
|
|
// 第二步:比对成功后,调用通知框架,xxx账号登录成功
|
|
|
|
|
StpUtil.login(10001);
|
|
|
|
|
return SaResult.ok("登录成功");
|
|
|
|
|
}
|
|
|
|
|
return SaResult.error("登录失败");
|
|
|
|
|
}
|
|
|
|
|
```
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:框架抛出的权限不足异常,我想根据自定义提示信息,可以吗?
|
2022-05-06 10:31:46 +08:00
|
|
|
|
可以,在全局异常拦截器里捕获`NotPermissionException`,可以通过`getPermission()`获取没有通过认证的权限码,可以据此自定义返回信息
|
2021-02-09 14:39:17 +08:00
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
``` java
|
|
|
|
|
@RestControllerAdvice
|
|
|
|
|
public class GlobalExceptionHandler {
|
|
|
|
|
// 全局 NotPermissionException 异常捕获
|
|
|
|
|
@ExceptionHandler(NotPermissionException.class)
|
|
|
|
|
public SaResult handlerException(NotPermissionException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
return SaResult.error("缺少权限:" + e.getPermission());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
2021-02-09 14:39:17 +08:00
|
|
|
|
|
2023-04-30 01:40:48 +08:00
|
|
|
|
### Q:在 SaInterceptor 中,注解鉴权总是先于路由拦截鉴权执行,能调整一下顺序吗?
|
|
|
|
|
框架没有提供直接的 API,但你有以下两种方式可以做到这一点:
|
|
|
|
|
- 方式1:将 SaInterceptor 里的代码复制出来一份,按照你的需求改一下,然后使用你这个自定义的拦截器,不再使用官方的。
|
|
|
|
|
- 方式2:注册两次 SaInterceptor 拦截器,例如:
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
@Configuration
|
|
|
|
|
public class SaTokenConfigure implements WebMvcConfigurer {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void addInterceptors(InterceptorRegistry registry) {
|
|
|
|
|
// 路由拦截鉴权
|
|
|
|
|
registry.addInterceptor(new SaInterceptor(r -> {
|
|
|
|
|
// 路由拦截鉴权的代码 ...
|
|
|
|
|
}).isAnnotation(false)).addPathPatterns("/**");
|
|
|
|
|
|
|
|
|
|
// 打开注解鉴权
|
|
|
|
|
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
如上,第一个完成路由拦截鉴权功能,第二个完成注解鉴权功能。
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:我的项目权限模型不是RBAC模型,很复杂,可以集成吗?
|
2021-02-09 14:39:17 +08:00
|
|
|
|
无论什么模型,只要能把一个用户具有的所有权限塞到一个List里返回给框架,就能集成
|
|
|
|
|
|
|
|
|
|
|
2022-09-25 00:53:29 +08:00
|
|
|
|
### Q:StpInterface 接口的 方法,在什么时候执行?
|
|
|
|
|
每次鉴权时执行,例如你调用了 `StpUtil.checkgetPermission("xxx")` 方法,框架就会调用底层的 `StpInterface#getPermissionList` 方法来获取权限数据。
|
|
|
|
|
|
|
|
|
|
如果你的 `getPermissionList` 里有读数据库的代码,那么你每鉴一次权,系统将访问一次数据库。如果要减小性能消耗,可以把权限数据放在缓存中,参考:[把权限放在缓存里](/fun/jur-cache)。
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:当我配置不并发登录时,每次登陆都会产生一个新的 Token,旧 Token 依然被保存在 Redis 中,框架为什么不删除呢?
|
2021-09-15 01:15:45 +08:00
|
|
|
|
首先,不删除旧 Token 的原因是为了在旧 Token 再次访问系统时提示他:已被顶下线。
|
|
|
|
|
|
|
|
|
|
而且这个 Token 不会永远留在 `Redis` 里,在其 TTL 到期后就会自动清除,如果你想让它立即消失,可以:
|
|
|
|
|
|
|
|
|
|
- 方法一:配置文件把 `is-concurrent` 和 `is-share` 都打开,这样每次登陆都会复用以前的旧 Token,就不会有废弃 Token 产生了。
|
2022-09-24 01:33:40 +08:00
|
|
|
|
- 方法二:每次登录前把先调用注销方法 `StpUtil.logout(10001)` ,把这个账号的旧登录都给清除了。
|
|
|
|
|
- 方法三:写一个定时任务查询 Redis 值进行删除。
|
2021-09-15 01:15:45 +08:00
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:我使用过滤器鉴权 or 全局拦截器鉴权,结果 Swagger 不能访问了,我应该排除哪些地址?
|
2021-09-15 01:15:45 +08:00
|
|
|
|
尝试加上排除 `"/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**" ,"/doc.html/**","/error","/favicon.ico"`
|
|
|
|
|
|
|
|
|
|
不同版本可能会有所不同,其实在前端摁一下 `F12` 看看哪个 url 报错排除哪个就行了(另附:注解鉴权是不需要排除的,因为 `Swagger` 本身也没有使用 Sa-Token 的注解)
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:SaRouter.match 有多个路径需要排除怎么办?
|
2022-09-24 01:33:40 +08:00
|
|
|
|
可以点进去源码看一下,`SaRouter.match`方法有多个重载,可以放一个集合, 例如:
|
|
|
|
|
``` java
|
|
|
|
|
SaRouter.match("/**").notMatch("/login", "/reg").check(r -> StpUtil.checkLogin());
|
|
|
|
|
```
|
2021-02-09 14:39:17 +08:00
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:为什么StpUtil.login() 不能直接写入一个User对象?
|
2021-09-15 01:15:45 +08:00
|
|
|
|
`StpUtil.login()`只是为了给当前会话做个唯一标记,通常写入`UserId`即可,如果要存储User对象,可以使用`StpUtil.getSession()`获取Session对象进行存储。
|
2021-02-09 14:39:17 +08:00
|
|
|
|
|
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
### Q:前后端分离模式下和普通模式有何不同?
|
|
|
|
|
主要是失去了`Cookie`无法自动化保存和提交`token秘钥`,可以参考章节:[前后端分离](/up/not-cookie)
|
2021-02-09 14:39:17 +08:00
|
|
|
|
|
|
|
|
|
|
2023-03-26 11:30:17 +08:00
|
|
|
|
### Q:前后端分离时,前端提交的 header 参数是叫 token 还是 satoken 还是 tokenName?
|
2021-09-15 01:15:45 +08:00
|
|
|
|
默认是satoken,如果想换一个名字,更改一下配置文件的`tokenName`即可。
|
2021-02-09 14:39:17 +08:00
|
|
|
|
|
2022-09-24 01:33:40 +08:00
|
|
|
|
|
|
|
|
|
### Q:一个账号拥有哪些权限,可以做成动态的吗?
|
|
|
|
|
权限本来就是动态的,框架预留的 `StpInterface` 接口,就是为了让你可以写任意代码来获取数据
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Q:路由拦截鉴权,可以做成动态的吗?
|
2022-09-24 01:40:30 +08:00
|
|
|
|
参考:[把路由拦截鉴权动态化](/fun/dynamic-router-check)
|
2021-02-09 14:39:17 +08:00
|
|
|
|
|
2022-09-25 12:07:44 +08:00
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:我不想让框架自动操作Cookie,怎么办?
|
2021-02-09 14:39:17 +08:00
|
|
|
|
在配置文件将`isReadCookie`值配置为`false`
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:怎么关掉每次启动时的字符画打印?
|
2021-06-16 17:48:21 +08:00
|
|
|
|
在配置文件将`isPrint`值配置为`false`
|
2021-02-09 14:39:17 +08:00
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:StpUtil.getSession()必须登录后才能调用吗?如果我想在用户未登录之前存储一些数据应该怎么办?
|
2023-05-15 18:23:18 +08:00
|
|
|
|
`StpUtil.getSession()`获取的是`Account-Session`,必须登录后才能使用,如果需要在未登录状态下也使用Session功能,请使用`Token-Session` <br>
|
|
|
|
|
步骤:先在配置文件里将`tokenSessionCheckLogin`配置为`false`,然后通过`StpUtil.getTokenSession()`获取Session 。或者直接调用 `StpUtil.getAnonTokenSession()` 获取匿名 Token-Session。
|
2021-01-31 23:28:42 +08:00
|
|
|
|
|
2020-02-06 00:52:49 +08:00
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:我只使用header来传输token,还需要打开Cookie模式吗?
|
2021-03-02 11:01:59 +08:00
|
|
|
|
不需要,如果只使用header来传输token,可以在配置文件关闭Cookie模式,例:`isReadCookie=false`
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:我想让用户修改密码后立即掉线重新登录,应该怎么做?
|
2021-03-04 10:13:00 +08:00
|
|
|
|
框架内置 [强制指定账号下线] 的APi,在执行修改密码逻辑之后调用此API即可: `StpUtil.logout()`
|
|
|
|
|
|
2021-08-01 05:39:31 +08:00
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:代码鉴权、注解鉴权、路由拦截鉴权,我该如何选择?
|
2021-08-01 05:39:31 +08:00
|
|
|
|
这个问题没有标准答案,这里只能给你提供一些建议,从鉴权粒度的角度来看:
|
|
|
|
|
1. 路由拦截鉴权:粒度最粗,只能粗略的拦截一个模块进行权限认证
|
|
|
|
|
2. 注解鉴权:粒度较细,可以详细到方法级,比较灵活
|
|
|
|
|
3. 代码鉴权:粒度最细,不光可以控制到方法级,甚至可以if语句决定是否鉴权
|
|
|
|
|
|
|
|
|
|
So:从鉴权粒度的角度来看,需要针对一个模块鉴权的时候,就用路由拦截鉴权,需要控制到方法级的时候,就用注解鉴权,需要根据条件判断是否鉴权的时候,就用代码鉴权
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:Sa-Token的全局过滤器我应该怎么指定它的优先级呢?
|
2021-09-15 01:15:45 +08:00
|
|
|
|
为了保证相关组件能够及时初始化,框架默认给过滤器注册的优先级为-100,如果你想更改优先级,直接在注册过滤器的方法上加上 `@Order(xxx)` 即可覆盖框架的默认配置
|
|
|
|
|
|
2021-08-31 01:11:26 +08:00
|
|
|
|
|
2023-03-27 17:20:49 +08:00
|
|
|
|
### Q:timeout 过期了,获取到的 NotLoginException 场景值是-2,按照文档说的应该是-3吧。是我理解的不对还是操作有误?
|
2023-03-26 11:30:17 +08:00
|
|
|
|
你的理解是对的,但是框架现在只能做到返回-2,因为 token 过期后,就从 Redis 中消失了,框架没法分辨这个 token 是曾经有过然后过期的,还是从来就没有在Redis中存在过,
|
|
|
|
|
所以只能统一抛出-2,这个行为也和具体使用的 SaTokenDao 有关联,例如集成 sa-token-jwt 插件后,框架就能分辨出来是 token 过期了,抛出-3。
|
|
|
|
|
|
|
|
|
|
|
2022-08-31 18:29:17 +08:00
|
|
|
|
### Q:还是有不明白到的地方?
|
2023-03-26 11:30:17 +08:00
|
|
|
|
请在`gitee` 、 `github` 提交 `issues`,或者加入qq群交流,[群链接](/more/join-group)
|
2021-01-31 23:28:42 +08:00
|
|
|
|
|