diff --git a/README.md b/README.md
index a69d3a5b..6c4f21f7 100644
--- a/README.md
+++ b/README.md
@@ -56,8 +56,8 @@ public String insert(SysUser user) {
将某个账号踢下线(待到对方再次访问系统时会抛出`NotLoginException`异常)
``` java
-// 使账号id为 10001 的会话强制注销登录
-StpUtil.logoutByLoginId(10001);
+// 将账号id为 10001 的会话踢下线
+StpUtil.kickout(10001);
```
在 Sa-Token 中,绝大多数功能都可以 **一行代码** 完成:
@@ -66,14 +66,14 @@ StpUtil.login(10001); // 标记当前会话登录的账号id
StpUtil.getLoginId(); // 获取当前会话登录的账号id
StpUtil.isLogin(); // 获取当前会话是否已经登录, 返回true或false
StpUtil.logout(); // 当前会话注销登录
-StpUtil.logoutByLoginId(10001); // 让账号为10001的会话注销登录(踢人下线)
+StpUtil.kickout(10001); // 将账号为10001的会话踢下线
StpUtil.hasRole("super-admin"); // 查询当前账号是否含有指定角色标识, 返回true或false
StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指定权限, 返回true或false
StpUtil.getSession(); // 获取当前账号id的Session
StpUtil.getSessionByLoginId(10001); // 获取账号id为10001的Session
StpUtil.getTokenValueByLoginId(10001); // 获取账号id为10001的token令牌值
StpUtil.login(10001, "PC"); // 指定设备标识登录,常用于“同端互斥登录”
-StpUtil.logoutByLoginId(10001, "PC"); // 指定设备标识进行强制注销 (不同端不受影响)
+StpUtil.kickout(10001, "PC"); // 指定账号指定设备标识踢下线 (不同端不受影响)
StpUtil.openSafe(120); // 在当前会话开启二级认证,有效期为120秒
StpUtil.checkSafe(); // 校验当前会话是否处于二级认证有效期内,校验失败会抛出异常
StpUtil.switchTo(10044); // 将当前会话身份临时切换为其它账号
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java
index 850fa360..b6cfc10b 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java
@@ -111,7 +111,7 @@ public class SaManager {
}
/**
- * 容器操作 Bean
+ * 上下文 Bean
*/
private volatile static SaTokenContext saTokenContext;
public static void setSaTokenContext(SaTokenContext saTokenContext) {
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java
index b507bd95..7abe3b86 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java
@@ -42,8 +42,8 @@ public @interface SaCheckPermission {
*
*
*
- * 例2: orRole={"admin", "manager", "staff"},具有三个角色其一即可
- * 例3: orRole={"admin, manager, staff"},必须三个角色同时具备
+ * 例2: orRole = {"admin", "manager", "staff"},具有三个角色其一即可
+ * 例3: orRole = {"admin, manager, staff"},必须三个角色同时具备
*
*/
String[] orRole() default {};
diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java
index a6375d52..9113aaf0 100644
--- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java
+++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java
@@ -1,7 +1,6 @@
package com.pj.satoken;
-import javax.annotation.PostConstruct;
-
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotatedElementUtils;
@@ -10,7 +9,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.pj.util.AjaxJson;
-import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
@@ -77,12 +75,12 @@ public class SaTokenConfigure implements WebMvcConfigurer {
/**
* 重写 Sa-Token 框架内部算法策略
*/
- @PostConstruct
+ @Autowired
public void rewriteSaStrategy() {
// 重写Sa-Token的注解处理器,增加注解合并功能
- SaStrategy.me.setGetAnnotation((element, annotationClass) -> {
- return AnnotatedElementUtils.getMergedAnnotation(element, SaCheckLogin.class);
- });
+ SaStrategy.me.getAnnotation = (element, annotationClass) -> {
+ return AnnotatedElementUtils.getMergedAnnotation(element, annotationClass);
+ };
}
}
diff --git a/sa-token-demo/sa-token-demo-thymeleaf/src/main/resources/templates/index.html b/sa-token-demo/sa-token-demo-thymeleaf/src/main/resources/templates/index.html
index 97b3addc..3886256b 100644
--- a/sa-token-demo/sa-token-demo-thymeleaf/src/main/resources/templates/index.html
+++ b/sa-token-demo/sa-token-demo-thymeleaf/src/main/resources/templates/index.html
@@ -14,7 +14,7 @@
登录之后才能显示:value
- 不登录之后才能显示:value
+ 不登录才能显示:value
具有角色 admin 才能显示:value
同时具备多个角色才能显示:value
@@ -28,7 +28,7 @@
从SaSession中取值:
-
+
diff --git a/sa-token-doc/doc/README.md b/sa-token-doc/doc/README.md
index 05e60d8d..bef14a9c 100644
--- a/sa-token-doc/doc/README.md
+++ b/sa-token-doc/doc/README.md
@@ -58,8 +58,8 @@ public String insert(SysUser user) {
将某个账号踢下线(待到对方再次访问系统时会抛出`NotLoginException`异常)
``` java
-// 使账号id为 10001 的会话强制注销登录
-StpUtil.logoutByLoginId(10001);
+// 将账号id为 10001 的会话踢下线
+StpUtil.kickout(10001);
```
在 Sa-Token 中,绝大多数功能都可以 **一行代码** 完成:
@@ -68,14 +68,14 @@ StpUtil.login(10001); // 标记当前会话登录的账号id
StpUtil.getLoginId(); // 获取当前会话登录的账号id
StpUtil.isLogin(); // 获取当前会话是否已经登录, 返回true或false
StpUtil.logout(); // 当前会话注销登录
-StpUtil.logoutByLoginId(10001); // 让账号为10001的会话注销登录(踢人下线)
+StpUtil.kickout(10001); // 将账号为10001的会话踢下线
StpUtil.hasRole("super-admin"); // 查询当前账号是否含有指定角色标识, 返回true或false
StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指定权限, 返回true或false
StpUtil.getSession(); // 获取当前账号id的Session
StpUtil.getSessionByLoginId(10001); // 获取账号id为10001的Session
StpUtil.getTokenValueByLoginId(10001); // 获取账号id为10001的token令牌值
StpUtil.login(10001, "PC"); // 指定设备标识登录,常用于“同端互斥登录”
-StpUtil.logoutByLoginId(10001, "PC"); // 指定设备标识进行强制注销 (不同端不受影响)
+StpUtil.kickout(10001, "PC"); // 指定账号指定设备标识踢下线 (不同端不受影响)
StpUtil.openSafe(120); // 在当前会话开启二级认证,有效期为120秒
StpUtil.checkSafe(); // 校验当前会话是否处于二级认证有效期内,校验失败会抛出异常
StpUtil.switchTo(10044); // 将当前会话身份临时切换为其它账号
diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md
index 8482b98c..04d39842 100644
--- a/sa-token-doc/doc/_sidebar.md
+++ b/sa-token-doc/doc/_sidebar.md
@@ -29,7 +29,7 @@
- [会话治理](/up/search-session)
- [全局侦听器](/up/global-listener)
- [全局过滤器](/up/global-filter)
- - [多账号验证](/up/many-account)
+ - [多账号认证](/up/many-account)
- **单点登录**
@@ -63,6 +63,7 @@
- [Quick-Login快速登录插件](/plugin/quick-login)
- [Alone独立Redis插件](/plugin/alone-redis)
- [持久层扩展](/plugin/dao-extend)
+ - [和 Thymeleaf 集成](/plugin/thymeleaf-extend)
- **其它**
- [更新日志](/more/update-log)
diff --git a/sa-token-doc/doc/lib/index.css b/sa-token-doc/doc/lib/index.css
index 824a01ce..93c1a9b3 100644
--- a/sa-token-doc/doc/lib/index.css
+++ b/sa-token-doc/doc/lib/index.css
@@ -61,6 +61,14 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
.lang-xml .token.tag *{color: #db2d20;}
.lang-xml .token.attr-value{color: #A6E22E;}
+/* html语言样式优化 */
+.lang-html .token.comment{color: #CDAB53;}
+.lang-html .token.tag *{color: #db2d20;}
+.lang-html .token.tag .attr-name,
+.lang-html .token.tag .attr-name *{color: #A6E22E; opacity: 0.9;}
+.lang-html .token.tag .attr-value,
+.lang-html .token.tag .attr-value *{color: #E6DB74; opacity: 0.9;}
+
/* java语言样式优化 */
.main-box .lang-java{color: #01a252 !important;; opacity: 1;}
.lang-java .token.keyword{color: #db2d20;}
diff --git a/sa-token-doc/doc/more/common-action.md b/sa-token-doc/doc/more/common-action.md
index 2e7299ad..a6796af7 100644
--- a/sa-token-doc/doc/more/common-action.md
+++ b/sa-token-doc/doc/more/common-action.md
@@ -12,6 +12,7 @@ SaManager.getStpInterface(); // 获取权限认证对象
SaManager.getSaTokenAction(); // 获取框架行为对象
SaManager.getSaTokenContext(); // 获取上下文处理对象
SaManager.getSaTokenListener(); // 获取侦听器对象
+SaManager.getSaTemp(); // 获取临时令牌验证模块对象
SaManager.getStpLogic("type"); // 获取指定账号类型的StpLogic对象
```
diff --git a/sa-token-doc/doc/plugin/thymeleaf-extend.md b/sa-token-doc/doc/plugin/thymeleaf-extend.md
new file mode 100644
index 00000000..e33a7dd4
--- /dev/null
+++ b/sa-token-doc/doc/plugin/thymeleaf-extend.md
@@ -0,0 +1,125 @@
+# Thymeleaf 标签方言
+
+本插件的作用是让我们可以在 Thymeleaf 页面中使用 Sa-Token 相关API,俗称 —— 标签方言。
+
+---
+
+### 1、引入依赖
+首先我们确保项目已经引入 Thymeleaf 依赖,然后在此基础上继续添加:
+
+``` xml
+
+
+ cn.dev33
+ sa-token-dialect-thymeleaf
+ ${sa.top.version}
+
+```
+
+
+### 2、注册标签方言对象
+在 SaTokenConfigure 配置类中注册 Bean
+``` java
+@Configuration
+public class SaTokenConfigure {
+ // Sa-Token 标签方言 (Thymeleaf版)
+ @Bean
+ public SaTokenDialect getSaTokenDialect() {
+ return new SaTokenDialect();
+ }
+}
+```
+
+
+### 3、使用标签方言
+然后我们就可以愉快的使用在 Thymeleaf 页面中使用标签方言了
+
+##### 3.1、登录判断
+``` html
+标签方言测试页面
+
+ 登录之后才能显示:
+ value
+
+
+ 不登录才能显示:
+ value
+
+```
+
+##### 3.2、角色判断
+``` html
+
+ 具有角色 admin 才能显示:
+ value
+
+
+ 同时具备多个角色才能显示:
+ value
+
+
+ 只要具有其中一个角色就能显示:
+ value
+
+
+ 不具有角色 admin 才能显示:
+ value
+
+```
+
+##### 3.3、权限判断
+``` html
+
+ 具有权限 user-add 才能显示:
+ value
+
+
+ 同时具备多个权限才能显示:
+ value
+
+
+ 只要具有其中一个权限就能显示:
+ value
+
+
+ 不具有权限 user-add 才能显示:
+ value
+
+```
+
+
+### 4、调用 Sa-Token 相关API
+
+以上的标签方言,可以满足我们大多数场景下的权限判断,然后有时候我们依然需要更加灵活的在页面中调用 Sa-Token 框架API
+
+首先在 SaTokenConfigure 配置类中为 Thymeleaf 配置全局对象:
+
+``` java
+public class SaTokenConfigure{
+ // ... 其它代码
+
+ // 为 Thymeleaf 注入全局变量,以便在页面中调用 Sa-Token 的方法
+ @Autowired
+ private void configureThymeleafStaticVars(ThymeleafViewResolver viewResolver) {
+ viewResolver.addStaticVariable("stp", StpUtil.stpLogic);
+ }
+}
+```
+
+然后我们就可以在页面上调用 StpLogic 的 API 了,例如:
+
+``` html
+调用 StpLogic 方法调用测试
+
+ 从SaSession中取值:
+
+
+```
+
+
+
+
+
+
+
+
diff --git a/sa-token-doc/doc/sso/sso-server.md b/sa-token-doc/doc/sso/sso-server.md
index 6bbc2b95..b998bc91 100644
--- a/sa-token-doc/doc/sso/sso-server.md
+++ b/sa-token-doc/doc/sso/sso-server.md
@@ -181,16 +181,16 @@ public class SaSsoServerApplication {

-可以看到这个页面非常简陋,这是因为我们以上的代码示例,主要目标是为了带大家从零搭建一个可用的SSO认证服务端,所以就对一些不太必要的步骤做了简化
+可以看到这个页面目前非常简陋,这是因为我们以上的代码示例,主要目标是为了带大家从零搭建一个可用的SSO认证服务端,所以就对一些不太必要的步骤做了简化。
大家可以下载运行一下官方仓库里的示例`/sa-token-demo/sa-token-demo-sso-server/`,里面有制作好的登录页面:

-默认账号密码为:`sa / 123456`,大家先别着急点击登录,因为我们还没有搭建对应的 Client 端项目,
+默认账号密码为:`sa / 123456`,先别着急点击登录,因为我们还没有搭建对应的 Client 端项目,
真实项目中我们是不会直接从浏览器访问 `/sso/auth` 授权地址的,我们需要在 Client 端点击登录按钮重定向而来。
-现在我们先来看看除了 `/sso/auth` 统一授权地址,这个 SSO-Server 认证中心还开放了哪些API呢,且往下看
+现在我们先来看看除了 `/sso/auth` 统一授权地址,这个 SSO-Server 认证中心还开放了哪些API。
### 5、API 列表
@@ -244,7 +244,7 @@ http://{host}:{port}/sso/checkTicket
| 参数 | 是否必填 | 说明 |
| :-------- | :-------- | :-------- |
| ticket | 是 | 在步骤 5.1 中授权重定向时的 ticket 参数 |
-| ssoLogoutCall | 否 | 单点注销时的回调通知地址,只在SSO模式三时需要携带此参数|
+| ssoLogoutCall | 否 | 单点注销时的回调通知地址,只在SSO模式三单点注销时需要携带此参数|
返回值场景:
- 返回空,代表校验失败。
@@ -267,7 +267,7 @@ http://{host}:{port}/sso/logout
此接口有两种调用方式
-##### 方式一:在前端页面引导用户直接跳转,并带有 back 参数
+##### 方式一:在 Client 的前端页面引导用户直接跳转,并带有 back 参数
例如:`http://{host}:{port}/sso/logout?back=xxx`,代表用户注销成功后返回back地址
##### 方式二:在 Client 的后端通过 http 工具来调用
diff --git a/sa-token-doc/doc/sso/sso-type1.md b/sa-token-doc/doc/sso/sso-type1.md
index 5dc420b5..b17b583c 100644
--- a/sa-token-doc/doc/sso/sso-type1.md
+++ b/sa-token-doc/doc/sso/sso-type1.md
@@ -40,17 +40,19 @@ OK,所有理论就绪,下面开始实战:
``` yml
sa-token:
cookie:
- # 配置Cookie作用域 (这个配置原本是被注释掉的,现在我们将其打开)
+ # 配置Cookie作用域
domain: stp.com
```
-注:在SSO模式一测试完毕之后,一定要将这个配置再次注释掉,因为模式一与模式二三使用不同的授权流程,这行配置会影响到我们模式二和模式三的正常运行。
+这个配置原本是被注释掉的,现在将其打开。另外我们格外需要注意:
+在SSO模式一测试完毕之后,一定要将这个配置再次注释掉,因为模式一与模式二三使用不同的授权流程,这行配置会影响到我们模式二和模式三的正常运行。
+
### 4、搭建 Client 端项目
-> 整合示例在官方仓库的 `/sa-token-demo/sa-token-demo-sso1-client/`,如遇到难点可结合源码进行测试学习。
+> 搭建示例在官方仓库的 `/sa-token-demo/sa-token-demo-sso1-client/`,如遇到难点可结合源码进行测试学习。
#### 4.1、引入依赖
diff --git a/sa-token-doc/doc/sso/sso-type3.md b/sa-token-doc/doc/sso/sso-type3.md
index 0099a389..b9fc6a27 100644
--- a/sa-token-doc/doc/sso/sso-type3.md
+++ b/sa-token-doc/doc/sso/sso-type3.md
@@ -122,7 +122,7 @@ public Object myinfo() {
5. Server 端注销下线。
6. 单点注销完成。
-这些逻辑 Sa-Token 内部已经封装完毕,你只需按照文章增加以下配置即可:
+这些逻辑 Sa-Token 内部已经封装完毕,你只需按照文档增加以下配置即可:
#### 4.1、SSO-Client 端新增配置
diff --git a/sa-token-doc/doc/up/global-listener.md b/sa-token-doc/doc/up/global-listener.md
index ff5a83f5..b352abee 100644
--- a/sa-token-doc/doc/up/global-listener.md
+++ b/sa-token-doc/doc/up/global-listener.md
@@ -12,6 +12,7 @@
### 自定义侦听器实现
新建`MySaTokenListener.java`,继承`SaTokenListener`接口,并添加上注解`@Component`,保证此类被`SpringBoot`扫描到
+
``` java
/**
* 自定义侦听器的实现
@@ -33,13 +34,13 @@ public class MySaTokenListener implements SaTokenListener {
/** 每次被踢下线时触发 */
@Override
- public void doLogoutByLoginId(String loginType, Object loginId, String tokenValue, String device) {
+ public void doKickout(String loginType, Object loginId, String tokenValue) {
// ...
}
/** 每次被顶下线时触发 */
@Override
- public void doReplaced(String loginType, Object loginId, String tokenValue, String device) {
+ public void doReplaced(String loginType, Object loginId, String tokenValue) {
// ...
}
diff --git a/sa-token-doc/doc/up/many-account.md b/sa-token-doc/doc/up/many-account.md
index e9b72be6..2632dbc7 100644
--- a/sa-token-doc/doc/up/many-account.md
+++ b/sa-token-doc/doc/up/many-account.md
@@ -1,4 +1,4 @@
-# 多账号验证
+# 多账号认证
---
### 0、需求场景
@@ -80,48 +80,20 @@ public String info() {
我们期待一种`[注解继承/合并]`的能力,即:自定义一个注解,标注上`@SaCheckLogin(type = "user")`,然后在方法上标注这个自定义注解,效果等同于标注`@SaCheckLogin(type = "user")`
-很遗憾,JDK默认的注解处理器并没有提供这种`[注解继承/合并]`的能力,不过好在我们可以利用Spring的注解处理器,达到同样的目的
+很遗憾,JDK默认的注解处理器并没有提供这种`[注解继承/合并]`的能力,不过好在我们可以利用 Spring 的注解处理器,达到同样的目的
1. 重写Sa-Token默认的注解处理器
``` java
-/**
- * 继承Sa-Token行为Bean默认实现, 重写部分逻辑
- */
-@Component
-public class MySaTokenAction extends SaTokenActionDefaultImpl {
-
- /**
- * 重写Sa-Token的注解处理器,加强注解合并功能
- */
- @Override
- protected void validateAnnotation(AnnotatedElement target) {
-
- // 校验 @SaCheckLogin 注解
- if(AnnotatedElementUtils.isAnnotated(target, SaCheckLogin.class)) {
- SaCheckLogin at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckLogin.class);
- SaManager.getStpLogic(at.type()).checkByAnnotation(at);
- }
-
- // 校验 @SaCheckRole 注解
- if(AnnotatedElementUtils.isAnnotated(target, SaCheckRole.class)) {
- SaCheckRole at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckRole.class);
- SaManager.getStpLogic(at.type()).checkByAnnotation(at);
- }
-
- // 校验 @SaCheckPermission 注解
- if(AnnotatedElementUtils.isAnnotated(target, SaCheckPermission.class)) {
- SaCheckPermission at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckPermission.class);
- SaManager.getStpLogic(at.type()).checkByAnnotation(at);
- }
-
- // 校验 @SaCheckSafe 注解
- if(AnnotatedElementUtils.isAnnotated(target, SaCheckSafe.class)) {
- SaCheckSafe at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckSafe.class);
- SaManager.getStpLogic(null).checkByAnnotation(at);
- }
- }
-
+@Configuration
+public class SaTokenConfigure {
+ @Autowired
+ public void rewriteSaStrategy() {
+ // 重写Sa-Token的注解处理器,增加注解合并功能
+ SaStrategy.me.getAnnotation = (element, annotationClass) -> {
+ return AnnotatedElementUtils.getMergedAnnotation(element, annotationClass);
+ };
+ }
}
```
@@ -184,6 +156,3 @@ public class StpUserUtil {
再次调用 `StpUserUtil.login(10001)` 进行登录授权时,token的名称将不再是 `satoken`,而是我们重写后的 `satoken-user`
-
-
-> 不同体系账号在登录时设置不同的token有效期等信息,详见[登录时指定token有效期](/up/remember-me?id=登录时指定token有效期)
\ No newline at end of file
diff --git a/sa-token-doc/doc/up/mock-person.md b/sa-token-doc/doc/up/mock-person.md
index b6432a86..9743d70e 100644
--- a/sa-token-doc/doc/up/mock-person.md
+++ b/sa-token-doc/doc/up/mock-person.md
@@ -14,8 +14,8 @@ Sa-Token在api设计时充分考虑了这一点,暴露出多个api进行此类
// 获取指定账号10001的`tokenValue`值
StpUtil.getTokenValueByLoginId(10001);
-// 将账号10001的会话注销登录(踢人下线)
-StpUtil.logoutByLoginId(10001);
+// 将账号10001的会话注销登录
+StpUtil.logout(10001);
// 获取账号10001的Session对象, 如果session尚未创建, 则新建并返回
StpUtil.getSessionByLoginId(10001);
diff --git a/sa-token-doc/doc/up/mutex-login.md b/sa-token-doc/doc/up/mutex-login.md
index 308f0c57..72300661 100644
--- a/sa-token-doc/doc/up/mutex-login.md
+++ b/sa-token-doc/doc/up/mutex-login.md
@@ -21,10 +21,10 @@ StpUtil.login(10001, "PC");
#### 指定设备标识强制注销
``` java
-// 指定`账号id`和`设备标识`进行强制注销 (踢人下线)
-StpUtil.logoutByLoginId(10001, "PC");
+// 指定`账号id`和`设备标识`进行强制注销
+StpUtil.logout(10001, "PC");
```
-如果第二个参数填写null或不填,代表将这个账号id所有在线端踢下线,被踢出者再次访问系统时会抛出 `NotLoginException` 异常,场景值=`-5`
+如果第二个参数填写null或不填,代表将这个账号id所有在线端强制注销,被踢出者再次访问系统时会抛出 `NotLoginException` 异常,场景值=`-2`
#### 查询当前登录的设备标识
@@ -40,5 +40,3 @@ StpUtil.getLoginDevice();
StpUtil.getTokenValueByLoginId(10001, "APP");
```
-
-> 不同设备账号在登录时设置不同的token有效期等信息, 详见[登录时指定token有效期](/up/remember-me?id=登录时指定token有效期)
\ No newline at end of file
diff --git a/sa-token-doc/doc/up/token-style.md b/sa-token-doc/doc/up/token-style.md
index a4220704..dbd8fdb7 100644
--- a/sa-token-doc/doc/up/token-style.md
+++ b/sa-token-doc/doc/up/token-style.md
@@ -37,27 +37,24 @@ Sa-Token默认的token生成策略是uuid风格,其模样类似于:`623368f0
如果你觉着以上风格都不是你喜欢的类型,那么你还可以**自定义token生成策略**,来定制化token生成风格
-怎么做呢?只需要重写`SaTokenAction`接口的`createToken`方法即可
+怎么做呢?只需要重写 `SaStrategy` 策略类的 `createToken` 算法即可
#### 参考步骤如下:
-1、新建文件`MySaTokenAction.java`,继承`SaTokenActionDefaultImpl`默认实现类, 并添加上注解`@Component`,保证此类被`springboot`扫描到
+1、在`SaTokenConfigure`配置类中添加代码:
``` java
-package com.pj.satoken;
-
-import org.springframework.stereotype.Component;
-import cn.dev33.satoken.action.SaTokenActionDefaultImpl;
-
-/**
- * 继承Sa-Token行为Bean默认实现, 重写部分逻辑
- */
-@Component
-public class MySaTokenAction extends SaTokenActionDefaultImpl {
- // 重写token生成策略
- @Override
- public String createToken(Object loginId, String loginType) {
- return SaFoxUtil.getRandomString(60); // 随机60位字符串
- }
+@Configuration
+public class SaTokenConfigure {
+ /**
+ * 重写 Sa-Token 框架内部算法策略
+ */
+ @Autowired
+ public void rewriteSaStrategy() {
+ // 重写 Token 生成策略
+ SaStrategy.me.createToken = (loginId, loginType) -> {
+ return SaFoxUtil.getRandomString(60); // 随机60位长度字符串
+ };
+ }
}
```
@@ -67,42 +64,3 @@ gfuPSwZsnUhwgz08GTCH4wOgasWtc3odP4HLwXJ7NDGOximTvT4OlW19zeLH
```
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/sa-token-doc/doc/use/at-check.md b/sa-token-doc/doc/use/at-check.md
index 4158ba89..8bc7fafb 100644
--- a/sa-token-doc/doc/use/at-check.md
+++ b/sa-token-doc/doc/use/at-check.md
@@ -89,14 +89,30 @@ public AjaxJson atJurOr() {
}
```
-
mode有两种取值:
- `SaMode.AND`, 标注一组权限,会话必须全部具有才可通过校验
- `SaMode.OR`, 标注一组权限,会话只要具有其一即可通过校验
+### 4、角色权限双重 “or校验”
+假设有以下业务场景:一个接口在具体权限 `user-add` 或角色 `admin` 时可以调通。怎么写?
-### 4、在业务逻辑层使用注解鉴权
+``` java
+// 注解式鉴权:只要具有其中一个权限即可通过校验
+@RequestMapping("userAdd")
+@SaCheckPermission(value = "user-add", orRole = "admin")
+public AjaxJson userAdd() {
+ return AjaxJson.getSuccessData("用户信息");
+}
+```
+
+orRole 字段代表权限认证未通过时的次要选择,两者只要其一认证成功即可通过校验,其有三种写法:
+- 写法一:`orRole = "admin"`,代表需要拥有角色 admin 。
+- 写法二:`orRole = {"admin", "manager", "staff"}`,代表具有三个角色其一即可。
+- 写法三:`orRole = {"admin, manager, staff"}`,代表必须同时具有三个角色。
+
+
+### 5、在业务逻辑层使用注解鉴权
疑问:我能否将注解写在其它架构层呢,比如业务逻辑层?
使用拦截器模式,只能在`Controller层`进行注解鉴权,如需在任意层级使用注解鉴权,请参考:[AOP注解鉴权](/plugin/aop-at)
diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md
index 74b7dc64..42694d62 100644
--- a/sa-token-doc/doc/use/config.md
+++ b/sa-token-doc/doc/use/config.md
@@ -33,7 +33,7 @@ sa-token:
### 方式2、通过代码配置
-方式1:
+模式1:
``` java
/**
* Sa-Token代码方式进行配置
@@ -59,7 +59,7 @@ public class SaTokenConfigure {
}
```
-方式2:
+模式2:
``` java
// 以代码的方式配置Sa-Token-Config
@Autowired
@@ -69,7 +69,7 @@ public void configSaToken(SaTokenConfig config) {
}
```
-PS:两者的区别在于:**`方式1会覆盖yml中的配置,方式2会与yml中的配置合并`**
+PS:两者的区别在于:**`模式1会覆盖yml中的配置,模式2会与yml中的配置合并`**
---
@@ -96,6 +96,18 @@ PS:两者的区别在于:**`方式1会覆盖yml中的配置,方式2会与y
| basic | String | "" | Http Basic 认证的账号和密码 [参考:Http Basic 认证](/up/basic-auth) |
| currDomain | null | "" | 配置当前项目的网络访问地址 |
| sso | Object | new SaSsoConfig() | SSO 单点登录相关配置 |
+| cookie | Object | new SaCookieConfig() | Cookie配置对象 |
+
+Cookie相关配置:
+
+| 参数名称 | 类型 | 默认值 | 说明 |
+| :-------- | :-------- | :-------- | :-------- |
+| domain | String | null | 作用域(写入Cookie时显式指定的作用域, 常用于单点登录二级域名共享Cookie的场景) |
+| path | String | / | 路径,默认写在域名根路径下 |
+| secure | Boolean | false | 是否只在 https 协议下有效 |
+| httpOnly | Boolean | false | 是否禁止 js 操作 Cookie |
+| sameSite | String | Lax | 第三方限制级别(Strict=完全禁止,Lax=部分允许,None=不限制) |
+
### 单点登录相关配置
@@ -130,7 +142,7 @@ Client 端:
sa-token:
# SSO-相关配置
sso:
- # SSO-Server端 单点登录地址
+ # SSO-Server端 单点登录授权地址
auth-url: http://sa-sso-server.com:9000/sso/auth
```
diff --git a/sa-token-doc/doc/use/jur-auth.md b/sa-token-doc/doc/use/jur-auth.md
index 14f39365..58333e04 100644
--- a/sa-token-doc/doc/use/jur-auth.md
+++ b/sa-token-doc/doc/use/jur-auth.md
@@ -75,16 +75,16 @@ public class StpInterfaceImpl implements StpInterface {
然后就可以用以下api来鉴权了
``` java
-// 当前账号是否含有指定权限, 返回true或false
+// 判断:当前账号是否含有指定权限, 返回true或false
StpUtil.hasPermission("user-update");
-// 当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException
+// 校验:当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException
StpUtil.checkPermission("user-update");
-// 当前账号是否含有指定权限 [指定多个,必须全部验证通过]
+// 校验:当前账号是否含有指定权限 [指定多个,必须全部验证通过]
StpUtil.checkPermissionAnd("user-update", "user-delete");
-// 当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]
+// 校验:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]
StpUtil.checkPermissionOr("user-update", "user-delete");
```
@@ -95,16 +95,16 @@ StpUtil.checkPermissionOr("user-update", "user-delete");
在Sa-Token中,角色和权限可以独立验证
``` java
-// 当前账号是否含有指定角色标识, 返回true或false
+// 判断:当前账号是否拥有指定角色, 返回true或false
StpUtil.hasRole("super-admin");
-// 当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
+// 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
StpUtil.checkRole("super-admin");
-// 当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
+// 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
StpUtil.checkRoleAnd("super-admin", "shop-admin");
-// 当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
+// 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
StpUtil.checkRoleOr("super-admin", "shop-admin");
```
diff --git a/sa-token-doc/doc/use/kick.md b/sa-token-doc/doc/use/kick.md
index 234f310e..b3413f96 100644
--- a/sa-token-doc/doc/use/kick.md
+++ b/sa-token-doc/doc/use/kick.md
@@ -6,25 +6,28 @@
---
-### 根据账号id踢人
-让指定账号id的会话注销登录,例如:
-
+### 1、强制注销
``` java
-// 使账号id为10001的会话注销登录(踢人下线),待到10001再次访问系统时会抛出`NotLoginException`异常,场景值为-5
-StpUtil.logoutByLoginId(10001);
+StpUtil.logout(10001); // 强制指定账号注销下线
+StpUtil.logout(10001, "PC"); // 强制指定账号指定端注销下线
+StpUtil.logoutByTokenValue("token"); // 强制指定 Token 注销下线
```
-### 根据Token令牌踢人
-你还可以让指定token的会话注销登录
+
+### 2、踢人下线
``` java
-// 使账号id为10001的会话注销登录
-StpUtil.logoutByTokenValue("xxxx-xxxx-xxxx-xxxx-xxxx");
+StpUtil.kickout(10001); // 将指定账号踢下线
+StpUtil.kickout(10001, "PC"); // 将指定账号指定端踢下线
+StpUtil.kickoutByTokenValue("token"); // 将指定 Token 踢下线
```
-此方法直接删除了`token->uid`的映射关系,对方再次访问时提示:`token无效`,场景值为-2
+
+强制注销 和 踢人下线 的区别在于:
+- 强制注销等价于对方主动调用了注销方法,再次访问会提示:Token无效。
+- 踢人下线不会清除Token信息,而是将其打上特定标记,再次访问会提示:Token已被踢下线。
-### 账号封禁
+### 3、账号封禁
对于违规账号,有时候我们仅仅将其踢下线还是远远不够的,我们还需要对其进行**账号封禁**防止其再次登录
``` java
@@ -49,7 +52,7 @@ StpUtil.untieDisable(10001);
如果需要将其封禁后立即掉线,可采取先踢再封禁的策略,例如:
``` java
// 先踢下线
-StpUtil.logoutByLoginId(10001);
+StpUtil.kickout(10001);
// 再封禁账号
StpUtil.disable(10001, 86400);
```
diff --git a/sa-token-doc/doc/use/route-check.md b/sa-token-doc/doc/use/route-check.md
index ee532e36..0a9add93 100644
--- a/sa-token-doc/doc/use/route-check.md
+++ b/sa-token-doc/doc/use/route-check.md
@@ -9,7 +9,7 @@
-### 1、注册路由拦截器
+### 1、注册 Sa-Token 路由拦截器
以`SpringBoot2.0`为例, 新建配置类`SaTokenConfigure.java`
``` java
@Configuration
@@ -17,39 +17,44 @@ public class SaTokenConfigure implements WebMvcConfigurer {
// 注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
- // 注册Sa-Token的路由拦截器,并排除登录接口或其他可匿名访问的接口地址 (与注解拦截器无关)
- registry.addInterceptor(new SaRouteInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/doLogin");
+ // 注册Sa-Token的路由拦截器
+ registry.addInterceptor(new SaRouteInterceptor())
+ .addPathPatterns("/**")
+ .excludePathPatterns("/user/doLogin");
}
}
```
-以上代码,我们注册了一个登录验证拦截器,并且排除了`/user/doLogin`接口用来开放登录(除了`/user/doLogin`以外的所有接口都需要登录才能访问)
+以上代码,我们注册了一个登录认证拦截器,并且排除了`/user/doLogin`接口用来开放登录(除了`/user/doLogin`以外的所有接口都需要登录才能访问)
那么我们如何进行权限认证拦截呢,且往下看
-### 2、自定义权限验证规则
-你可以使用函数式编程自定义验证规则
+### 2、校验函数详解
+你可以使用函数式编程自定义认证规则,例如:
``` java
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
- // 注册路由拦截器,自定义验证规则
+ // 注册路由拦截器,自定义认证规则
registry.addInterceptor(new SaRouteInterceptor((req, res, handler)->{
// 根据路由划分模块,不同模块不同鉴权
- SaRouter.match("/user/**", () -> StpUtil.checkPermission("user"));
- SaRouter.match("/admin/**", () -> StpUtil.checkPermission("admin"));
- SaRouter.match("/goods/**", () -> StpUtil.checkPermission("goods"));
- SaRouter.match("/orders/**", () -> StpUtil.checkPermission("orders"));
- SaRouter.match("/notice/**", () -> StpUtil.checkPermission("notice"));
- SaRouter.match("/comment/**", () -> StpUtil.checkPermission("comment"));
+ SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
+ SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
+ SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
+ SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
+ SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
+ SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
})).addPathPatterns("/**");
}
}
```
-### 3、完整示例
-所有用法示例:
+SaRouter.match() 匹配函数有两个参数:
+- 参数一:要匹配的path路由。
+- 参数二:要执行的校验函数。
+
+在校验函数内不只可以使用 `StpUtil.checkPermission("xxx")` 进行权限校验,你还可以写任意代码,例如:
``` java
@Configuration
@@ -57,41 +62,28 @@ public class SaTokenConfigure implements WebMvcConfigurer {
// 注册Sa-Token的拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
- // 注册路由拦截器,自定义验证规则
+ // 注册路由拦截器,自定义认证规则
registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> {
- // 登录验证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
- SaRouter.match("/**", "/user/doLogin", () -> StpUtil.checkLogin());
+ // 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
+ SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());
+
+ // 角色认证 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证
+ SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
+
+ // 权限认证 -- 不同模块认证不同权限
+ SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
+ SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
+ SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
+ SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
+ SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
+ SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
- // 登录验证 -- 排除多个路径
- SaRouter.match(Arrays.asList("/**"), Arrays.asList("/user/doLogin", "/user/reg"), () -> StpUtil.checkLogin());
-
- // 角色认证 -- 拦截以 admin 开头的路由,必须具备[admin]角色或者[super-admin]角色才可以通过认证
- SaRouter.match("/admin/**", () -> StpUtil.checkRoleOr("admin", "super-admin"));
-
- // 权限认证 -- 不同模块, 校验不同权限
- SaRouter.match("/user/**", () -> StpUtil.checkPermission("user"));
- SaRouter.match("/admin/**", () -> StpUtil.checkPermission("admin"));
- SaRouter.match("/goods/**", () -> StpUtil.checkPermission("goods"));
- SaRouter.match("/orders/**", () -> StpUtil.checkPermission("orders"));
- SaRouter.match("/notice/**", () -> StpUtil.checkPermission("notice"));
- SaRouter.match("/comment/**", () -> StpUtil.checkPermission("comment"));
-
- // 匹配 restful 风格路由
- SaRouter.match("/article/get/{id}", () -> StpUtil.checkPermission("article"));
-
- // 检查请求方式
- SaRouter.match("/notice/**", () -> {
- if(req.getMethod().equals(HttpMethod.GET.toString())) {
- StpUtil.checkPermission("notice");
- }
- });
-
- // 提前退出 (执行SaRouter.stop()后会直接退出匹配链)
- SaRouter.match("/test/back", () -> SaRouter.stop());
-
- // 在多账号模式下,可以使用任意StpUtil进行校验
- SaRouter.match("/user/**", () -> StpUserUtil.checkLogin());
+ // 甚至你可以随意的写一个打印语句
+ SaRouter.match("/**", r -> System.out.println("----啦啦啦----"));
+
+ // 连缀写法
+ SaRouter.match("/**").check(r -> System.out.println("----啦啦啦----"));
})).addPathPatterns("/**");
}
@@ -99,44 +91,80 @@ public class SaTokenConfigure implements WebMvcConfigurer {
```
-### 4、提前退出匹配链条
+### 3、匹配特征详解
+
+除了上述示例的 path 路由匹配,还可以根据很多其它特征进行匹配,以下是所有可匹配的特征:
+
+``` java
+// 基础写法样例:匹配一个path,执行一个校验函数
+SaRouter.match("/user/**").check(r -> StpUtil.checkLogin());
+
+// 根据 path 路由匹配 ——— 支持写多个path,支持写 restful 风格路由
+SaRouter.match("/user/**", "/goods/**", "/art/get/{id}").check( /* 要执行的校验函数 */ );
+
+// 根据 path 路由排除匹配
+SaRouter.match("/**").notMatch("*.html", "*.css", "*.js").check( /* 要执行的校验函数 */ );
+
+// 根据请求类型匹配
+SaRouter.match(SaHttpMethod.GET).check( /* 要执行的校验函数 */ );
+
+// 根据一个 boolean 条件进行匹配
+SaRouter.match( StpUtil.isLogin() ).check( /* 要执行的校验函数 */ );
+
+// 根据一个返回 boolean 结果的lambda表达式匹配
+SaRouter.match( r -> StpUtil.isLogin() ).check( /* 要执行的校验函数 */ );
+
+// 多个条件一起使用
+SaRouter.match(SaHttpMethod.GET).match("/**").check( /* 要执行的校验函数 */ );
+
+// 可以无限连缀下去
+SaRouter
+ .match(SaHttpMethod.GET)
+ .match("/admin/**")
+ .match("/user/**")
+ .notMatch("/**/*.js")
+ .notMatch("/**/*.css")
+ // ....
+ .check( /* 只有上述所有条件都匹配成功,才会执行最后的check校验函数 */ );
+```
+
+
+
+### 4、提前退出匹配链
使用 `SaRouter.stop()` 可以提前退出匹配链,例:
``` java
registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> {
- SaRouter.match("/**", () -> System.out.println("进入1"));
- SaRouter.match("/**", () -> {System.out.println("进入2"); SaRouter.stop();});
- SaRouter.match("/**", () -> System.out.println("进入3"));
+ SaRouter.match("/**").check(r -> System.out.println("进入1"));
+ SaRouter.match("/**").check(r -> System.out.println("进入2")).stop();
+ SaRouter.match("/**").check(r -> System.out.println("进入3"));
})).addPathPatterns("/**");
```
如上示例,代码运行至第2条匹配链时,会在stop函数处提前退出整个匹配函数,从而忽略掉剩余的所有match匹配
除了`stop()`函数,`SaRouter`还提供了 `back()` 函数,用于:停止匹配,结束执行,直接向前端返回结果
``` java
-SaRouter.match("/user/back", () -> SaRouter.back("执行back函数后将停止匹配,也不会进入Controller,而是直接将此参数作为返回值输出到前端"));
+// 执行back函数后将停止匹配,也不会进入Controller,而是直接将 back参数 作为返回值输出到前端
+SaRouter.match("/user/back").back("参数");
```
-`stop()` 与 `back()` 函数的区别在于:
+stop() 与 back() 函数的区别在于:
- `SaRouter.stop()` 会停止匹配,进入Controller。
- `SaRouter.back()` 会停止匹配,直接返回结果到前端。
-
-
-
-
-
-
\ No newline at end of file
+
+free() 的作用是:打开一个独立的作用域,使内部的 stop() 不再一次性跳出整个 Auth 函数,而是仅仅跳出当前 free 作用域。
+