From 3bec16627e99b89bbb814d50689f563cf03cb008 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 11 Oct 2021 01:09:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=B0=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E7=89=B9=E6=80=A7=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +- .../main/java/cn/dev33/satoken/SaManager.java | 2 +- .../satoken/annotation/SaCheckPermission.java | 4 +- .../java/com/pj/satoken/SaTokenConfigure.java | 12 +- .../src/main/resources/templates/index.html | 4 +- sa-token-doc/doc/README.md | 8 +- sa-token-doc/doc/_sidebar.md | 3 +- sa-token-doc/doc/lib/index.css | 8 + sa-token-doc/doc/more/common-action.md | 1 + sa-token-doc/doc/plugin/thymeleaf-extend.md | 125 +++++++++++++ sa-token-doc/doc/sso/sso-server.md | 10 +- sa-token-doc/doc/sso/sso-type1.md | 8 +- sa-token-doc/doc/sso/sso-type3.md | 2 +- sa-token-doc/doc/up/global-listener.md | 5 +- sa-token-doc/doc/up/many-account.md | 53 ++---- sa-token-doc/doc/up/mock-person.md | 4 +- sa-token-doc/doc/up/mutex-login.md | 8 +- sa-token-doc/doc/up/token-style.md | 70 ++------ sa-token-doc/doc/use/at-check.md | 20 ++- sa-token-doc/doc/use/config.md | 20 ++- sa-token-doc/doc/use/jur-auth.md | 16 +- sa-token-doc/doc/use/kick.md | 27 +-- sa-token-doc/doc/use/route-check.md | 166 ++++++++++-------- 23 files changed, 352 insertions(+), 232 deletions(-) create mode 100644 sa-token-doc/doc/plugin/thymeleaf-extend.md 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-server-init-login.png](https://oss.dev33.cn/sa-token/doc/sso/sso-server-init-login.png 's-w-sh') -可以看到这个页面非常简陋,这是因为我们以上的代码示例,主要目标是为了带大家从零搭建一个可用的SSO认证服务端,所以就对一些不太必要的步骤做了简化 +可以看到这个页面目前非常简陋,这是因为我们以上的代码示例,主要目标是为了带大家从零搭建一个可用的SSO认证服务端,所以就对一些不太必要的步骤做了简化。 大家可以下载运行一下官方仓库里的示例`/sa-token-demo/sa-token-demo-sso-server/`,里面有制作好的登录页面: ![sso-server-init-login2.png](https://oss.dev33.cn/sa-token/doc/sso/sso-server-init-login2.png 's-w-sh') -默认账号密码为:`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 作用域。 +