diff --git a/sa-token-doc/doc/more/common-questions.md b/sa-token-doc/doc/more/common-questions.md
index ce24eec3..8e57bdd1 100644
--- a/sa-token-doc/doc/more/common-questions.md
+++ b/sa-token-doc/doc/more/common-questions.md
@@ -91,6 +91,45 @@
3. 如果以上步骤处理后仍然没有效果,加群说明一下复现步骤
+### 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 -> {
+ System.out.println("--------- flag 2");
+ StpUtil.checkLogin(); // 登录校验,只有会话登录后才能通过这句代码
+ }))
+ .addPathPatterns("/user/**")
+ .excludePathPatterns("/user/doLogin");
+ }
+}
+```
+
+在启动时 `flag 1` 被打印出来,才证明拦截器注册成功了,在访问请求时 `flag 2` 被打印出来,才证明请求进入了拦截器。
+
+如果拦截器没有注册成功,则:
+- 可能1:SpringBoot 版本较高(`>= 2.6.0`),请尝试在启动类加上 `@EnableWebMvc` 注解再重新启动。
+- 可能2:`SaTokenConfigure` 配置类不在启动类的同包或者子包下,导致没有被 SpringBoot 扫描到。
+- 可能3:`SaTokenConfigure` 配置类在启动类的同包或者子包下,但启动类上加了 `@ComponentScan("com.xxx")` 注解,导致包扫描范围不正确,请将此注解删除或移动到其它配置类上。
+- 可能4:项目属于 Maven 多模块项目,`SaTokenConfigure` 和启动类没有在一个模块,且启动类模块没有引入配置类的模块,导致加载不到。
+
+如果拦截器已经注册成功,但请求没有进入拦截器:
+- 可能1:你访问的 path,没有被 `.addPathPatterns("/user/**")` 拦截住。
+- 可能2:你访问的 path,被 `.excludePathPatterns("/xxx/xx")` 排除掉了。
+- 可能3:你访问的是另一个项目,请把当前项目停掉,看看你的请求还能不能访问成功。
+
+注:以上的排查步骤,对过滤器不生效的情形一样适用。
+
+
### Q:我使用拦截器鉴权时,明明排除了某个路径却仍然被拦截了?
- 可能1:你的项目可能是跨域了,先把跨域问题解决掉,参考:[解决跨域问题](/fun/cors-filter)
- 可能2:你访问的接口可能是404了,SpringBoot环境下如果访问接口404后,会被转发到`/error`,然后被再次拦截。请确保你访问的 path 有对应的 Controller 承接!
@@ -108,20 +147,22 @@ registry.addInterceptor(new SaInterceptor(handler -> {
### Q:有时候我不加 Token 也可以通过鉴权,请问是怎么回事?
-可能是Cookie帮你自动传了,在浏览器或 Postman 中会自动维护Cookie模式,如不需要可以在配置文件:`is-read-cookie: false`,然后重启项目再测试一下
+可能1:你访问的这个接口,根本就没有鉴权的代码,所以可以安全的访问通过。
+可能2:可能是 Cookie 帮你自动提交了 Token,在浏览器或 Postman 中会自动维护Cookie模式,如不需要可以在配置文件:`is-read-cookie: false`,然后重启项目再测试一下。
-### Q:一个User对象存进Session后,再取出来时报错:无法从User类型转换成User类型?
-群员亲测,当你打开热部署模式后,先存进去的对象,热刷新后再取出,会报错,关闭热刷新即可解决
+### Q:一个 User 对象存进 Session 后,再取出来时报错:无法从 User 类型转换成 User 类型?
+可能1:你的 User 类中途换了包名,导致存进去时和取出来时对不上,无法成功创建实例。
+可能2:你打开了代码热刷新模式,先存进去的对象,热刷新后再取出,会报错,关闭热刷新即可解决。
### Q:我配置了 active-timeout 值,但是当我每次续签时 Redis 中的 ttl 并没有更新,是不是 bug 了?
不更新是正常现象,`active-timeout`不是根据 ttl 计算的,是根据value值计算的,value 记录的是该 Token 最后访问系统的时间戳,
-每次验签时用:当前时间 - 时间戳 > active-timeout,来判断这个 Token 是否已经超时
+每次验签时用:当前时间 - 时间戳 > active-timeout,来判断这个 Token 是否已经超时。
### Q:整合 Redis 时先选择了默认jdk序列化,后又改成 jackson 序列化,程序开始报错,SerializationException?
-两者的序列化算法不一致导致的反序列化失败,如果要更改序列化方式,则需要先将 Redis 中历史数据清除,再做更新
+两者的序列化算法不一致导致的反序列化失败,如果要更改序列化方式,则需要先将 Redis 中历史数据清除,再做更新。
### Q:我加了 Sa-Token 的全局过滤器,浏览器报错跨域了怎么办?
@@ -180,8 +221,8 @@ springboot 集成 satoken redis 后, 一旦 springboot 切换版本就有可能
而且这个 Token 不会永远留在 `Redis` 里,在其 TTL 到期后就会自动清除,如果你想让它立即消失,可以:
- 方法一:配置文件把 `is-concurrent` 和 `is-share` 都打开,这样每次登陆都会复用以前的旧 Token,就不会有废弃 Token 产生了。
-- 方法二:每次登录前把先调用注销方法,把这个账号的旧登录都给清除了。
-- 方法三:写一个定时任务查询Redis值进行删除。
+- 方法二:每次登录前把先调用注销方法 `StpUtil.logout(10001)` ,把这个账号的旧登录都给清除了。
+- 方法三:写一个定时任务查询 Redis 值进行删除。
### Q:我使用过滤器鉴权 or 全局拦截器鉴权,结果 Swagger 不能访问了,我应该排除哪些地址?
@@ -192,8 +233,11 @@ springboot 集成 satoken redis 后, 一旦 springboot 切换版本就有可能
### Q:SaRouter.match 有多个路径需要排除怎么办?
-可以点进去源码看一下,`SaRouter.match`方法有多个重载,可以放一个集合, 例如:
-`SaRouter.match(/**).notMatch("/login", "/reg").check(r -> StpUtil.checkLogin());`
+可以点进去源码看一下,`SaRouter.match`方法有多个重载,可以放一个集合, 例如:
+
+``` java
+SaRouter.match("/**").notMatch("/login", "/reg").check(r -> StpUtil.checkLogin());
+```
### Q:为什么StpUtil.login() 不能直接写入一个User对象?
@@ -207,8 +251,55 @@ springboot 集成 satoken redis 后, 一旦 springboot 切换版本就有可能
### Q:前后台分离时,前端提交的 header 参数是叫 token 还是 satoken 还是 tokenName?
默认是satoken,如果想换一个名字,更改一下配置文件的`tokenName`即可。
-### Q:权限可以做成动态的吗?
-权限本来就是动态的,只有jwt那种模式才是非动态的
+
+### Q:一个账号拥有哪些权限,可以做成动态的吗?
+权限本来就是动态的,框架预留的 `StpInterface` 接口,就是为了让你可以写任意代码来获取数据
+
+
+### Q:路由拦截鉴权,可以做成动态的吗?
+框架提供的示例是硬代码写死的,不过稍微做一下改的,你就可以让他动态化,比如:
+``` java
+@Override
+public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(new SaInterceptor(handle -> {
+ SaRouter
+ .match("/**")
+ .notMatch(excludePaths())
+ .check(r -> StpUtil.checkLogin());
+ })).addPathPatterns("/**");
+}
+
+// 动态获取哪些 path 可以忽略鉴权
+public List excludePaths() {
+ // 此处仅为示例,实际项目你可以写任意代码来查询这些path
+ return Arrays.asList("/path1", "/path2", "/path3");
+}
+```
+
+如果不仅仅是登录校验,还需要鉴权,那也很简单:
+``` java
+@Override
+public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(new SaInterceptor(handle -> {
+ // 遍历校验规则,依次鉴权
+ Map rules = getAuthRules();
+ for (String path : rules.keySet()) {
+ SaRouter.match(path, () -> StpUtil.checkPermission(rules.get(path)));
+ }
+ })).addPathPatterns("/**");
+}
+
+// 动态获取鉴权规则
+public Map getAuthRules() {
+ // key 代表要拦截的 path,value 代表需要校验的权限
+ Map authMap = new LinkedHashMap<>();
+ authMap.put("/user/**", "user");
+ authMap.put("/admin/**", "admin");
+ authMap.put("/article/**", "article");
+ // 更多规则 ...
+ return authMap;
+}
+```
### Q:我不想让框架自动操作Cookie,怎么办?
diff --git a/sa-token-doc/doc/up/global-listener.md b/sa-token-doc/doc/up/global-listener.md
index 4b2395d6..8c97475a 100644
--- a/sa-token-doc/doc/up/global-listener.md
+++ b/sa-token-doc/doc/up/global-listener.md
@@ -153,7 +153,7 @@ public SaResult login() {
``` java
@Component
-public class MySaTokenListener implements SaTokenListenerForSimple {
+public class MySaTokenListener extends SaTokenListenerForSimple {
/*
* SaTokenListenerForSimple 对所有事件提供了空实现,通过继承此类,你只需重写一部分方法即可实现一个可用的侦听器。
*/