Compare commits

...

119 Commits
v1.42.0 ... dev

Author SHA1 Message Date
click33
b0d42821d7 docs: 完善文档 2025-06-07 11:59:57 +08:00
click33
ebc381772f release v1.44.0 .. 2025-06-07 01:22:29 +08:00
click33
d08f93bdc0 release v1.44.0 . 2025-06-07 01:08:39 +08:00
click33
c2fc4decef Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2025-06-07 00:40:48 +08:00
刘潇
f7378f3898
!340 feat:新增 loveqq-framework 启动器集成
Merge pull request !340 from kfyty/dev
2025-06-06 16:40:30 +00:00
click33
7bde74bc51 release v1.44.0 2025-06-07 00:35:11 +08:00
kfyty725
5fc40a5af2 opt:loveqq-framework启动器支持java8 2025-06-04 21:31:41 +08:00
kfyty725
e13b263f27 feat:集成loveqq-framework示例 2025-06-04 17:48:49 +08:00
kfyty725
bd22a94a10 feat:集成loveqq-framework示例 2025-06-04 17:46:36 +08:00
kfyty725
be5ee2fc2b feat:loveqq-framework启动器 2025-06-04 16:12:23 +08:00
kfyty725
f4e7dac95f feat:loveqq-framework启动器 2025-06-04 15:20:00 +08:00
click33
e97cddb5e2 docs: 文档新增 sa-token-dubbo3 的说明 2025-06-04 00:16:39 +08:00
click33
e80369eb4b fix: 修复 sa-token-dubbo 与 sa-token-dubbo3 每次调用都强制需要上下文的问题。 2025-06-04 00:15:04 +08:00
click33
0cd3d66712 fix: sa-token-sso 模块 SaSsoClientModel 删除 isValidPushUrl 函数,避免其触发自动序列化操作导致无法存入 redis 2025-06-03 23:48:24 +08:00
click33
923b76a8db Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2025-06-03 20:26:52 +08:00
click33
a6b38430cd fix: 修复 SSO 模式三全端注销失效的问题 2025-06-03 20:26:33 +08:00
刘潇
e2c08f7dd2
!339 feat: 支持重写获取高级权限与低级权限的方法
Merge pull request !339 from xiumu/dev
2025-06-03 10:17:53 +00:00
xiumu
986111b10c feat: 支持重写获取高级权限与低级权限的方法
- 将获取高级权限以及低级权限的方法放到SaOAuth2DataLoader中, 可以自定义权限数据的加载来源
2025-06-02 17:21:41 +08:00
click33
2cf18309b2 fix: 修复 sso-server 前后端分离示例无法正常登录的问题 2025-05-29 17:08:42 +08:00
click33
d22ac1b7cf docs: 更新赞助者名单 2025-05-27 12:14:33 +08:00
click33
fece7081a9 docs: 更新离线版文档下载链接地址 2025-05-23 06:36:34 +08:00
click33
dc874c2275 docs: 增加版本更新导读文章视频链接 2025-05-17 10:26:49 +08:00
click33
5ab847c441 Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2025-05-17 07:31:17 +08:00
click33
f98db819ef release: v1.43.0 2025-05-17 07:30:28 +08:00
刘潇
2b5840dcbb
!335 为SaTokenInterceptor添加@Override注解
Merge pull request !335 from chengliejian/dev
2025-05-16 13:02:04 +00:00
click33
9913a901aa refactor: 重构 sa-token-redis-template、sa-token-redis-template-jdk-serializer 插件中 update 方法 ttl 获取方式改为毫秒,以减少 update 时的 ttl 计算误差。 2025-05-16 20:53:32 +08:00
click33
c22fb3efb1 fix: 修正文档与 test 模块部分细节错误 2025-05-16 17:09:16 +08:00
click33
fee9ef1643 feat(oauth2): SaOAuth2Util 新增 currentAccessToken()、currentClientToken(),简化读取 access_token、client_token 步骤 2025-05-16 06:36:27 +08:00
click33
6ce8f38aaf feat: 新增 sa-token-okhttps 插件,整合 OkHttps 作为请求处理器模块 2025-05-16 00:43:41 +08:00
click33
760cac764b refactor: 修复文档与注释细节点错误。 2025-05-16 00:19:46 +08:00
click33
edbd63f81b feat: SaInterceptor 新增 beforeAuth 认证前置函数 2025-05-15 22:32:54 +08:00
click33
a5ea1a3a4d docs: sso 章节和 oauth2 章节文档增加可重写策略说明 2025-05-15 21:47:56 +08:00
click33
df91c2ece0 refactor: API Sign 模块拆分独立插件包:sa-token-sign 2025-05-15 21:21:21 +08:00
click33
9fcaf89412 feat: SaTokenListener 侦听器 doRenewTimeout 方法添加 loginType 参数 2025-05-15 16:05:47 +08:00
click33
44c153fd19 refactor: API Key 模块拆分独立插件包:sa-token-apikey 2025-05-15 05:14:59 +08:00
click33
3edac001ce feat(code): SaCheckOr 注解添加 append 字段,用于抓取未预先定义的注解类型进行批量注解鉴权 2025-05-15 01:04:54 +08:00
click33
3e13a39244 docs(oauth2): 优化调整 oauth2 章节相关文档 2025-05-14 04:18:14 +08:00
click33
5b3a64b9fc refactor(oauth2): 优化调整 sa-token-oauth2 模块代码结构及注释 2025-05-14 03:30:31 +08:00
click33
0ed0c277df feat(oauth2): 新增 SaOAuth2Strategy.instance.userAuthorizeClientCheck 策略,用于检查指定用户是否可以授权指定应用 2025-05-13 03:59:35 +08:00
click33
f1089f697c feat(oauth2): 新增:多 Access-Token 并存 & 多 Refresh-Token 并存 & 多 Client-Token 并存 & 移除 Lower-Client-Token 模块
Closes: #IBHFD1, #IBLL4Q
fix: #724
2025-05-13 02:38:31 +08:00
click33
1304cb248d docs(oauth2): 文档新增重写 PasswordGrantTypeHandler 处理器示例 2025-05-11 15:08:29 +08:00
click33
04792f7290 docs: oauth2-server 示例添加真正表单 2025-05-11 14:58:35 +08:00
click33
9f52c4d399 fefactor(oauth2): 将认证流程回调从 SaOAuth2ServerConfig 转移到 SaOAuth2Strategy 2025-05-11 14:52:15 +08:00
click33
c4e34704d5 feat(oauth2): 对 OAuth2 Password 认证模式需要重写处理器添加强提醒 2025-05-11 14:27:05 +08:00
click33
2523d4b8df fix(oauth2): 修复 oidc 协议下,当用户数据变动后,id_token 仍是旧信息的问题 2025-05-10 21:45:52 +08:00
click33
a3c7568fc3 docs: 补充 sso 模块遗漏的配置字段介绍 2025-05-10 17:32:42 +08:00
click33
7c35e6a859 docs: 完善 QA:访问了一个不存在的路由,报错:SaTokenContext 上下文尚未初始化 2025-05-10 15:36:50 +08:00
click33
a27e1d85b6 feat(oauth2): SaClientModel 新增 isAutoConfirm 配置项,用于决定是否允许应用可以自动确认授权 2025-05-10 03:21:40 +08:00
click33
49622fbf2d refactor: 调整注释(修复 Http Digest 认证时 url 上带有查询参数时认证无法通过的问题) 2025-05-09 22:40:48 +08:00
刘潇
5543905505
!334 解决解析Digest参数字符串包含多个=导致认证失败的问题,如:url带参数的问题场景
Merge pull request !334 from Wien/dev
2025-05-09 14:35:56 +00:00
click33
6fc3b09581 feat(sso): 单点注销消息推送时忽略掉发起调用的 client,减少不必要的调用 2025-05-09 21:40:59 +08:00
click33
9dc6ade2cf refactor: 调整 solon sso 示例代码 2025-05-09 14:32:47 +08:00
刘潇
bb1702da0b
!338 修复 sa-token-demo-sso-server-solon 不能正常获取 SaSsoClientInfo 的问题
Merge pull request !338 from 西东/dev
2025-05-09 05:19:42 +00:00
noear
dc85fe660a fix: 修复 sa-token-demo-sso-server-solon 不能正常获取 SaSsoClientInfo 的问题 2025-05-09 10:14:30 +08:00
noear
bef2ae7c84 refactor: sa-token-solon-plugin 移除 json 适配代码(改由 sa-token 自由选择序列化扩展) 2025-05-09 10:08:41 +08:00
noear
c70152962a fix: sa-token-snack3 优化 objectToJson 序列化处理(增加类名,但不增加根类名) 2025-05-09 10:05:20 +08:00
noear
1c0831bd94 feat: noear-snack3 升为 3.2.133 2025-05-09 09:45:28 +08:00
noear
1391b4981a feat: noear-snack3 升为 3.2.132 2025-05-09 08:48:21 +08:00
noear
6da1359dcf feat: solon 升级为 3.2.1 2025-05-09 08:42:46 +08:00
noear
08fa9fe06a feat: solon 升级为 3.2.1 2025-05-09 08:39:56 +08:00
click33
cad172819a refactor: 调整 solon-sso 示例代码 2025-05-09 03:53:03 +08:00
click33
d6187e8c34 feat(sso): 注销回调推送消息增加 autoLogout 参数 2025-05-08 22:21:24 +08:00
click33
5d3b1f4455 docs: 完善 SSO 章节文档 2025-05-08 20:52:52 +08:00
click33
88f99c49fb refactor: 调整 SSO 相关示例 2025-05-08 20:50:30 +08:00
click33
2ecd52b3be feat(sso): 调整 SSO 示例适配最新版 & 新增 sso-resdk 示例 & 新增 sso-anon 示例 2025-05-06 23:26:49 +08:00
chengliejian
bfc06c19cf 为SaTokenInterceptor添加@Override注解 2025-05-06 16:00:30 +08:00
click33
213d98d848 refactor: 重构 sa-token-sso 模块代码及注释,提高代码可读性 2025-05-05 12:55:52 +08:00
click33
b59fa26edf Merge branch 'dev' of https://github.com/dromara/Sa-Token into dev 2025-05-04 10:42:36 +08:00
click33
c615e163cb
Merge pull request #629 from YuanErya/dev
修正文档,附AES对称加密从密码->密钥生成策略,方便其他语言开发者对接
2025-05-04 06:45:11 +08:00
click33
25e3a3f9cd
Merge pull request #703 from zhhal/dev
Update documentation for spring.web.resources.add-mappings configuration
2025-05-04 06:41:51 +08:00
刘潇
f6ec0fa465
!333 oauth2中, scope分割符支持加号
Merge pull request !333 from sonhuagao007/dev
2025-05-03 22:33:30 +00:00
刘潇
75eb78494b
!331 fix: 修复使用 sa-token-redis-template-jdk-serializer 时反序列化错误
Merge pull request !331 from wudp/dev
2025-05-03 22:31:37 +00:00
click33
f150209a4f feat(sso): sso-server 新增 jumpToRedirectUrlNotice 策略,用于授权重定向跳转之前的通知 2025-05-03 13:14:18 +08:00
click33
6f845fb6b8 feat(sso): 新增 convertCenterIdToLoginId、convertLoginIdToCenterId 策略函数,用于描述本地 LoginId 与认证中心 loginId 的转换规则 2025-05-03 12:45:09 +08:00
click33
6e9bb2b31a feat(sso): 新增 SSO Strategy 策略类 2025-05-03 12:04:14 +08:00
click33
1d9b730685 refactor: 优化 SSO demo 2025-05-03 11:30:49 +08:00
click33
ad4e8408fe refactor: 略微优化 sso 相关 demo 2025-05-03 06:46:31 +08:00
click33
62e5c9b19d refactor(sso): 封住化获取 client 标识值 2025-05-02 04:54:38 +08:00
click33
5aac119beb feat(sso): 单点注销支持单设备注销 2025-05-01 16:10:02 +08:00
click33
c2dea166e4 feat: 新增 StpUtil.getTerminalInfo() 查询设备信息、StpUtil.getLoginDeviceId() 查询登录设备id 2025-05-01 02:32:26 +08:00
Wien
3cb81149c1 解决解析Digest参数字符串包含多个=导致认证失败的问题,如:url带参数的问题场景 2025-04-30 17:04:07 +08:00
bbc
72c91ff0aa scope分割符支持加号 + 2025-04-30 13:42:13 +08:00
click33
0229459d8d refactor: 新增 TicketModel 对象,以便在 ticket 中储存更多信息 2025-04-30 11:27:14 +08:00
click33
66c431bb3e feat: SaLogoutParameter 新增 deviceId 参数,用于控制指定设备 id 的注销 2025-04-30 07:30:11 +08:00
click33
9ceebda9f5 Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2025-04-30 03:56:10 +08:00
click33
95cc77a8bc feat: sa-token-sso 模块新增消息推送机制 2025-04-30 03:55:42 +08:00
刘潇
6ef777e58f
!332 feat(sa-token): 在 SaCheckOr 注解中添加 apikey 支持
Merge pull request !332 from KairosSun/dev
2025-04-28 11:07:03 +00:00
click33
b53eac9269 feat: 新增 sa-token-forest 插件,用于在 Http 请求处理器模块整合 Forest 2025-04-26 23:50:49 +08:00
click33
0ae51a1b56 feat: 新增 http 请求处理器模块 2025-04-26 23:24:31 +08:00
Kairos
a17befcebb feat(sa-token): 在 SaCheckOr 注解中添加 apikey 支持
- 在 SaCheckOr 注解中添加 apikey 属性,用于设定 @SaCheckApiKey
- 更新 SaCheckOrHandler 类,支持处理新增的 apikey 属性- 此更新扩展了 SaCheckOr 注解的功能,使其能够支持 API 密钥的验证
2025-04-26 09:15:22 +08:00
click33
abdfb2305d Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2025-04-25 21:40:57 +08:00
click33
84506d49f0 feat: sso 模块新增配置文件方式启用“不同 client 不同秘钥”能力 2025-04-25 21:40:05 +08:00
刘潇
8992b17f7d
!329 feat: totp增加issuer字段
Merge pull request !329 from burningimlam/dev
2025-04-25 07:41:31 +00:00
click33
476910dffb feat: sso. 2025-04-25 15:39:44 +08:00
click33
79113c5848 feat: sso 模块新增 allowAnonClient 决定是否启用匿名 client & 新增 clients 配置项,用于单独配置每个 client 的授权信息 2025-04-25 15:39:11 +08:00
click33
2d777fbd22 docs: 新增 QA:在 idea 导入源码,运行报错:java: 程序包cn.dev33.satoken.oauth2不存在 2025-04-24 00:25:09 +08:00
click33
b5dae2e6cc docs: 修复 OAuth2 UnionId 章节相关不正确描述 2025-04-23 22:12:01 +08:00
click33
35d8ff06ca docs: 插图优化 2025-04-23 19:51:13 +08:00
wudp
7e5c2e6fce fix: 修复使用 sa-token-redis-template-jdk-serializer 时反序列化错误 2025-04-23 09:23:02 +08:00
click33
e6400a0cd5 docs: 优化副标题介绍 2025-04-23 02:50:12 +08:00
click33
2102d2c1f2 docs: SSO 模块新增思维导图说明 2025-04-23 02:41:34 +08:00
click33
a92fb8eee2 docs: readme 新增框架功能介绍图 2025-04-23 01:26:13 +08:00
click33
93566c58a4 docs: add ad: mianshiya & bianchengdaohang 2025-04-22 19:10:49 +08:00
click33
624d1645fa Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2025-04-22 18:08:15 +08:00
click33
3f86dfdc12 docs: 新增部分资源下载链接 2025-04-22 18:07:45 +08:00
刘潇
d3719ab423
!330 fix: 修复 sa-token-sanck3 SaSessionForSnack3Customized:getModel 接收 map 值时会出错的问题
Merge pull request !330 from 西东/dev
2025-04-18 03:34:36 +00:00
noear
4a8490c0c4 fix: 修复 sa-token-sanck3 SaSessionForSnack3Customized:getModel 接收 map 值时会出错的问题 2025-04-17 22:59:18 +08:00
click33
3658779d87 Merge branch 'dev' of https://github.com/dromara/Sa-Token into dev 2025-04-16 15:40:56 +08:00
click33
cc681672df fix: 修复 sa-token-dubbo 模块,部分场景下无法正确处理上下文的问题 2025-04-16 15:31:01 +08:00
click33
4d1040076b
Merge pull request #769 from mySingleLive/patch-1
update: 添加 Forest 的友情链接
2025-04-15 18:30:45 +08:00
公子骏
86ca5c7fcb
update: 添加 Forest 的友情链接 2025-04-15 18:28:58 +08:00
imlam
757e1b86a7 feat: totp增加issuer字段 2025-04-15 10:49:25 +08:00
click33
95f4d62c8e docs: 重写路由匹配算法修正为最新写法 2025-04-14 13:55:32 +08:00
click33
f6a14d4241 docs: 文档新增 API Key demo 仓库说明 2025-04-12 18:10:36 +08:00
click33
66d2fc6d1e docs: 新增QA:报错:SaTokenContext 上下文尚未初始化 2025-04-12 17:00:06 +08:00
click33
2ef879c75f demo: 新增示例:如何在响应式环境下的 Filter 里调用 Sa-Token 同步 API 2025-04-12 16:54:23 +08:00
click33
895941b5c8 feat: 新增 SSE 中使用 Sa-Token 示例 2025-04-11 18:17:35 +08:00
liuzhonghua
f2cc698ab8 docs:Update documentation for spring.web.resources.add-mappings configuration 2024-11-12 11:59:43 +08:00
YuanErya
72e18bd906 修正文档,附AES对称加密从密码->密钥生成策略,方便其他语言开发者对接。 2024-05-28 09:26:18 +08:00
423 changed files with 14765 additions and 4562 deletions

View File

@ -1,8 +1,8 @@
<p align="center">
<img alt="logo" src="https://sa-token.cc/logo.png" width="150" height="150">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.42.0</h1>
<h4 align="center">一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!</h4>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.44.0</h1>
<h4 align="center">开源、免费、轻量级 Java 权限认证框架,让鉴权变得简单、优雅!</h4>
<p align="center">
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg?theme=gvp"></a>
<a href="https://gitee.com/dromara/sa-token/members"><img src="https://gitee.com/dromara/sa-token/badge/fork.svg?theme=gvp"></a>
@ -23,6 +23,8 @@
Sa-Token 是一个轻量级 Java 权限认证框架目前拥有五大核心模块登录认证、权限认证、单点登录、OAuth2.0、微服务鉴权。
![sa-token-jss](https://oss.dev33.cn/sa-token/doc/home/sa-token-jss--tran.png)
要在 SpringBoot 项目中使用 Sa-Token你只需要在 pom.xml 中引入依赖:
``` xml
@ -30,7 +32,7 @@ Sa-Token 是一个轻量级 Java 权限认证框架,目前拥有五大核心
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.42.0</version>
<version>1.44.0</version>
</dependency>
```
@ -38,7 +40,7 @@ Sa-Token 是一个轻量级 Java 权限认证框架,目前拥有五大核心
<details>
<summary><b>简单示例展示:(点击展开 / 折叠)</b></summary>
<summary><b>简单示例展示:</b>(点击展开 / 折叠)</summary>
Sa-Token 旨在以简单、优雅的方式完成系统的权限认证部分,以登录认证为例,你只需要:
@ -90,13 +92,15 @@ registry.addInterceptor(new SaInterceptor(handler -> {
})).addPathPatterns("/**");
```
当你受够 Shiro、SpringSecurity 等框架的三拜九叩之后你就会明白相对于这些传统老牌框架Sa-Token 的 API 设计是多么的简单、优雅!
**如果您曾经使用过 Shiro、SpringSecurity在切换到 Sa-Token 后,您将体会到质的飞跃。**
<!-- 当你受够 Shiro、SpringSecurity 等框架的三拜九叩之后你就会明白相对于这些传统老牌框架Sa-Token 的 API 设计是多么的简单、优雅! -->
</details>
<details>
<summary> <b>核心模块一览:(点击展开 / 折叠)</b> </summary>
<summary> <b>核心模块一览:</b>(点击展开 / 折叠) </summary>
- **登录认证** —— 单端登录、多端登录、同端互斥登录、七天内免登录。
- **权限认证** —— 权限认证、角色认证、会话二级认证。
@ -139,12 +143,13 @@ registry.addInterceptor(new SaInterceptor(handler -> {
</details>
![sa-token-js](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-js4.png)
### SSO 单点登录
Sa-Token SSO 分为三种模式解决同域、跨域、共享Redis、跨Redis、前后端一体、前后端分离……等不同架构下的 SSO 接入问题:
![sa-token-jss](https://oss.dev33.cn/sa-token/doc/home/sa-token-sso--white.png)
| 系统架构 | 采用模式 | 简介 | 文档链接 |
| :-------- | :-------- | :-------- | :-------- |
| 前端同域 + 后端同 Redis | 模式一 | 共享Cookie同步会话 | [文档](https://sa-token.cc/doc.html#/sso/sso-type1)、[示例](https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-sso1-client) |
@ -193,6 +198,7 @@ Sa-Token-OAuth2 模块分为四种授权模式,解决不同场景下的授权
### 友情链接
- [[ OkHttps ]](https://gitee.com/ejlchina-zhxu/okhttps):轻量级 http 通信框架API无比优雅支持 WebSocket、Stomp 协议
- [[ Forest ]](https://gitee.com/dromara/forest):声明式与编程式双修,让天下没有难以发送的 HTTP 请求
- [[ Bean Searcher ]](https://github.com/ejlchina/bean-searcher):专注高级查询的只读 ORM使一行代码实现复杂列表检索
- [[ Jpom ]](https://gitee.com/dromara/Jpom):简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件。
- [[ TLog ]](https://gitee.com/dromara/TLog):一个轻量级的分布式日志标记追踪神器。

View File

@ -27,6 +27,7 @@ cd sa-token-demo-springboot3-redis & call mvn clean & cd ..
cd sa-token-demo-springboot-low-version & call mvn clean & cd ..
cd sa-token-demo-springboot-redis & call mvn clean & cd ..
cd sa-token-demo-springboot-redisson & call mvn clean & cd ..
cd sa-token-demo-sse & call mvn clean & cd ..
cd sa-token-demo-ssm & call mvn clean & cd ..
cd sa-token-demo-test & call mvn clean & cd ..
cd sa-token-demo-thymeleaf & call mvn clean & cd ..
@ -57,8 +58,9 @@ cd sa-token-demo-sso-server & call mvn clean & cd ..
cd sa-token-demo-sso1-client & call mvn clean & cd ..
cd sa-token-demo-sso2-client & call mvn clean & cd ..
cd sa-token-demo-sso3-client & call mvn clean & cd ..
cd sa-token-demo-sso3-client-test2 & call mvn clean & cd ..
cd sa-token-demo-sso3-client-nosdk & call mvn clean & cd ..
cd sa-token-demo-sso3-client-resdk & call mvn clean & cd ..
cd sa-token-demo-sso3-client-anon & call mvn clean & cd ..
cd ..
cd sa-token-demo-sso-for-solon

19
pom.xml
View File

@ -37,7 +37,7 @@
<!-- 一些属性 -->
<properties>
<revision>1.42.0</revision>
<revision>1.44.0</revision>
<jdk.version>1.8</jdk.version>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>
@ -104,8 +104,23 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<version>3.4.1</version>
<configuration>
<!-- 统一生成聚合文档,解决 mvn package 时控制台发出 javadoc 警告的问题 -->
<aggregate>true</aggregate>
<!-- 忽略部分 error 和 warning -->
<failOnError>false</failOnError>
<failOnWarnings>false</failOnWarnings>
<additionalOptions>-Xdoclint:none</additionalOptions>
<detectLinks>false</detectLinks>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
<execution>
<id>attach-javadocs</id>
<goals>

View File

@ -13,7 +13,7 @@
<url>https://github.com/dromara/sa-token</url>
<properties>
<revision>1.42.0</revision>
<revision>1.44.0</revision>
</properties>
<dependencyManagement>
@ -139,6 +139,16 @@
<artifactId>sa-token-redis-jackson</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-forest</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-okhttps</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisson-spring-boot-starter</artifactId>
@ -179,6 +189,16 @@
<artifactId>sa-token-oauth2</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-apikey</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sign</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-quick-login</artifactId>

View File

@ -15,9 +15,6 @@
*/
package cn.dev33.satoken;
import cn.dev33.satoken.apikey.SaApiKeyTemplate;
import cn.dev33.satoken.apikey.loader.SaApiKeyDataLoader;
import cn.dev33.satoken.apikey.loader.SaApiKeyDataLoaderDefaultImpl;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.config.SaTokenConfigFactory;
import cn.dev33.satoken.context.SaTokenContext;
@ -26,6 +23,8 @@ import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.http.SaHttpTemplate;
import cn.dev33.satoken.http.SaHttpTemplateDefaultImpl;
import cn.dev33.satoken.json.SaJsonTemplate;
import cn.dev33.satoken.json.SaJsonTemplateDefaultImpl;
import cn.dev33.satoken.listener.SaTokenEventCenter;
@ -35,7 +34,6 @@ import cn.dev33.satoken.same.SaSameTemplate;
import cn.dev33.satoken.secure.totp.SaTotpTemplate;
import cn.dev33.satoken.serializer.SaSerializerTemplate;
import cn.dev33.satoken.serializer.impl.SaSerializerTemplateForJson;
import cn.dev33.satoken.sign.SaSignTemplate;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
import cn.dev33.satoken.stp.StpLogic;
@ -201,6 +199,25 @@ public class SaManager {
return saJsonTemplate;
}
/**
* HTTP 转换器
*/
private volatile static SaHttpTemplate saHttpTemplate;
public static void setSaHttpTemplate(SaHttpTemplate saHttpTemplate) {
SaManager.saHttpTemplate = saHttpTemplate;
SaTokenEventCenter.doRegisterComponent("SaHttpTemplate", saHttpTemplate);
}
public static SaHttpTemplate getSaHttpTemplate() {
if (saHttpTemplate == null) {
synchronized (SaManager.class) {
if (saHttpTemplate == null) {
SaManager.saHttpTemplate = new SaHttpTemplateDefaultImpl();
}
}
}
return saHttpTemplate;
}
/**
* 序列化器
*/
@ -220,25 +237,6 @@ public class SaManager {
return saSerializerTemplate;
}
/**
* API 参数签名
*/
private volatile static SaSignTemplate saSignTemplate;
public static void setSaSignTemplate(SaSignTemplate saSignTemplate) {
SaManager.saSignTemplate = saSignTemplate;
SaTokenEventCenter.doRegisterComponent("SaSignTemplate", saSignTemplate);
}
public static SaSignTemplate getSaSignTemplate() {
if (saSignTemplate == null) {
synchronized (SaManager.class) {
if (saSignTemplate == null) {
SaManager.saSignTemplate = new SaSignTemplate();
}
}
}
return saSignTemplate;
}
/**
* Same-Token 同源系统认证模块
*/
@ -289,44 +287,6 @@ public class SaManager {
return totpTemplate;
}
/**
* ApiKey 数据加载器
*/
private volatile static SaApiKeyDataLoader apiKeyDataLoader;
public static void setSaApiKeyDataLoader(SaApiKeyDataLoader apiKeyDataLoader) {
SaManager.apiKeyDataLoader = apiKeyDataLoader;
SaTokenEventCenter.doRegisterComponent("SaApiKeyDataLoader", apiKeyDataLoader);
}
public static SaApiKeyDataLoader getSaApiKeyDataLoader() {
if (apiKeyDataLoader == null) {
synchronized (SaManager.class) {
if (apiKeyDataLoader == null) {
SaManager.apiKeyDataLoader = new SaApiKeyDataLoaderDefaultImpl();
}
}
}
return apiKeyDataLoader;
}
/**
* ApiKey 操作类
*/
private volatile static SaApiKeyTemplate apiKeyTemplate;
public static void setSaApiKeyTemplate(SaApiKeyTemplate apiKeyTemplate) {
SaManager.apiKeyTemplate = apiKeyTemplate;
SaTokenEventCenter.doRegisterComponent("SaApiKeyTemplate", apiKeyTemplate);
}
public static SaApiKeyTemplate getSaApiKeyTemplate() {
if (apiKeyTemplate == null) {
synchronized (SaManager.class) {
if (apiKeyTemplate == null) {
SaManager.apiKeyTemplate = new SaApiKeyTemplate();
}
}
}
return apiKeyTemplate;
}
// ------------------- StpLogic 相关 -------------------

View File

@ -15,10 +15,7 @@
*/
package cn.dev33.satoken.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
/**
* 批量注解鉴权只要满足其中一个注解即可通过验证
@ -81,4 +78,11 @@ public @interface SaCheckOr {
*/
SaCheckDisable[] disable() default {};
/**
* 需要追加抓取的注解 Class (只能填写 Sa-Token 相关注解类型)
*
* @return /
*/
Class<? extends Annotation>[] append() default {};
}

View File

@ -16,7 +16,7 @@
package cn.dev33.satoken.annotation.handler;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 所有注解处理器的父接口
@ -35,18 +35,18 @@ public interface SaAnnotationHandlerInterface<T extends Annotation> {
/**
* 所需要执行的校验方法
* @param at 注解对象
* @param method 被标注的注解的方法引用
* @param element 被标注的注解的元素(方法/)引用
*/
@SuppressWarnings("unchecked")
default void check(Annotation at, Method method) {
checkMethod((T) at, method);
default void check(Annotation at, AnnotatedElement element) {
checkMethod((T) at, element);
}
/**
* 所需要执行的校验方法转换类型后
* @param at 注解对象
* @param method 被标注的注解的方法引用
* @param element 被标注的注解的元素(方法/)引用
*/
void checkMethod(T at, Method method);
void checkMethod(T at, AnnotatedElement element);
}

View File

@ -19,7 +19,7 @@ import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.annotation.SaCheckDisable;
import cn.dev33.satoken.stp.StpLogic;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaCheckDisable 的处理器
@ -35,7 +35,7 @@ public class SaCheckDisableHandler implements SaAnnotationHandlerInterface<SaChe
}
@Override
public void checkMethod(SaCheckDisable at, Method method) {
public void checkMethod(SaCheckDisable at, AnnotatedElement element) {
_checkMethod(at.type(), at.value(), at.level());
}

View File

@ -18,7 +18,7 @@ package cn.dev33.satoken.annotation.handler;
import cn.dev33.satoken.annotation.SaCheckHttpBasic;
import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaCheckHttpBasic 的处理器
@ -34,7 +34,7 @@ public class SaCheckHttpBasicHandler implements SaAnnotationHandlerInterface<SaC
}
@Override
public void checkMethod(SaCheckHttpBasic at, Method method) {
public void checkMethod(SaCheckHttpBasic at, AnnotatedElement element) {
_checkMethod(at.realm(), at.account());
}

View File

@ -20,7 +20,7 @@ import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.httpauth.digest.SaHttpDigestUtil;
import cn.dev33.satoken.util.SaFoxUtil;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaCheckHttpDigest 的处理器
@ -36,7 +36,7 @@ public class SaCheckHttpDigestHandler implements SaAnnotationHandlerInterface<Sa
}
@Override
public void checkMethod(SaCheckHttpDigest at, Method method) {
public void checkMethod(SaCheckHttpDigest at, AnnotatedElement element) {
_checkMethod(at.username(), at.password(), at.realm(), at.value());
}

View File

@ -19,7 +19,7 @@ import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpLogic;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaCheckLogin 的处理器
@ -35,7 +35,7 @@ public class SaCheckLoginHandler implements SaAnnotationHandlerInterface<SaCheck
}
@Override
public void checkMethod(SaCheckLogin at, Method method) {
public void checkMethod(SaCheckLogin at, AnnotatedElement element) {
_checkMethod(at.type());
}

View File

@ -20,7 +20,7 @@ import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.strategy.SaAnnotationStrategy;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -39,8 +39,8 @@ public class SaCheckOrHandler implements SaAnnotationHandlerInterface<SaCheckOr>
}
@Override
public void checkMethod(SaCheckOr at, Method method) {
_checkMethod(at.login(), at.role(), at.permission(), at.safe(), at.httpBasic(), at.httpDigest(), at.disable(), method);
public void checkMethod(SaCheckOr at, AnnotatedElement element) {
_checkMethod(at.login(), at.role(), at.permission(), at.safe(), at.httpBasic(), at.httpDigest(), at.disable(), at.append(), element);
}
public static void _checkMethod(
@ -51,7 +51,8 @@ public class SaCheckOrHandler implements SaAnnotationHandlerInterface<SaCheckOr>
SaCheckHttpBasic[] httpBasic,
SaCheckHttpDigest[] httpDigest,
SaCheckDisable[] disable,
Method method
Class<? extends Annotation>[] append,
AnnotatedElement element
) {
// 先把所有注解塞到一个 list
List<Annotation> annotationList = new ArrayList<>();
@ -62,6 +63,12 @@ public class SaCheckOrHandler implements SaAnnotationHandlerInterface<SaCheckOr>
annotationList.addAll(Arrays.asList(disable));
annotationList.addAll(Arrays.asList(httpBasic));
annotationList.addAll(Arrays.asList(httpDigest));
for (Class<? extends Annotation> annotationClass : append) {
Annotation annotation = SaAnnotationStrategy.instance.getAnnotation.apply(element, annotationClass);
if(annotation != null) {
annotationList.add(annotation);
}
}
// 如果 atList 为空说明 SaCheckOr 上不包含任何注解校验我们直接跳过即可
if(annotationList.isEmpty()) {
@ -72,7 +79,7 @@ public class SaCheckOrHandler implements SaAnnotationHandlerInterface<SaCheckOr>
List<SaTokenException> errorList = new ArrayList<>();
for (Annotation item : annotationList) {
try {
SaAnnotationStrategy.instance.annotationHandlerMap.get(item.annotationType()).check(item, method);
SaAnnotationStrategy.instance.annotationHandlerMap.get(item.annotationType()).check(item, element);
// 只要有一个校验通过就可以直接返回了
return;
} catch (SaTokenException e) {

View File

@ -22,7 +22,7 @@ import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.util.SaFoxUtil;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaCheckPermission 的处理器
@ -38,7 +38,7 @@ public class SaCheckPermissionHandler implements SaAnnotationHandlerInterface<Sa
}
@Override
public void checkMethod(SaCheckPermission at, Method method) {
public void checkMethod(SaCheckPermission at, AnnotatedElement element) {
_checkMethod(at.type(), at.value(), at.mode(), at.orRole());
}

View File

@ -20,7 +20,7 @@ import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.stp.StpLogic;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaCheckRole 的处理器
@ -36,7 +36,7 @@ public class SaCheckRoleHandler implements SaAnnotationHandlerInterface<SaCheckR
}
@Override
public void checkMethod(SaCheckRole at, Method method) {
public void checkMethod(SaCheckRole at, AnnotatedElement element) {
_checkMethod(at.type(), at.value(), at.mode());
}

View File

@ -19,7 +19,7 @@ import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.annotation.SaCheckSafe;
import cn.dev33.satoken.stp.StpLogic;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaCheckSafe 的处理器
@ -35,7 +35,7 @@ public class SaCheckSafeHandler implements SaAnnotationHandlerInterface<SaCheckS
}
@Override
public void checkMethod(SaCheckSafe at, Method method) {
public void checkMethod(SaCheckSafe at, AnnotatedElement element) {
_checkMethod(at.type(), at.value());
}

View File

@ -18,10 +18,11 @@ package cn.dev33.satoken.annotation.handler;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.router.SaRouter;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaIgnore 的处理器
* <h2> v1.43.0 版本起SaIgnore 注解处理逻辑已转移到全局策略中此处理器代码仅做留档 </h2>
*
* @author click33
* @since 2024/8/2
@ -34,7 +35,7 @@ public class SaIgnoreHandler implements SaAnnotationHandlerInterface<SaIgnore> {
}
@Override
public void checkMethod(SaIgnore at, Method method) {
public void checkMethod(SaIgnore at, AnnotatedElement element) {
_checkMethod();
}

View File

@ -21,8 +21,6 @@ import cn.dev33.satoken.stp.parameter.enums.SaReplacedRange;
import cn.dev33.satoken.util.SaFoxUtil;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Sa-Token 配置类 Model
@ -223,21 +221,6 @@ public class SaTokenConfig implements Serializable {
*/
public SaCookieConfig cookie = new SaCookieConfig();
/**
* API 签名配置对象
*/
public SaSignConfig sign = new SaSignConfig();
/**
* API 签名配置 多实例
*/
public Map<String, SaSignConfig> signMany = new LinkedHashMap<>();
/**
* API Key 相关配置
*/
public SaApiKeyConfig apiKey = new SaApiKeyConfig();
/**
* @return token 名称 同时也是 cookie 名称提交 token 时参数的名称存储 token 时的 key 前缀
*/
@ -866,62 +849,6 @@ public class SaTokenConfig implements Serializable {
return this;
}
/**
* @return API 签名全局配置对象
*/
public SaSignConfig getSign() {
return sign;
}
/**
* @param sign API 签名全局配置对象
* @return 对象自身
*/
public SaTokenConfig setSign(SaSignConfig sign) {
this.sign = sign;
return this;
}
/**
* 获取 API 签名配置 多实例
*
* @return /
*/
public Map<String, SaSignConfig> getSignMany() {
return this.signMany;
}
/**
* 设置 API 签名配置 多实例
*
* @param signMany /
* @return /
*/
public SaTokenConfig setSignMany(Map<String, SaSignConfig> signMany) {
this.signMany = signMany;
return this;
}
/**
* API Key 相关配置
*
* @return /
*/
public SaApiKeyConfig getApiKey() {
return this.apiKey;
}
/**
* 设置 API Key 相关配置
*
* @param apiKey /
* @return /
*/
public SaTokenConfig setApiKey(SaApiKeyConfig apiKey) {
this.apiKey = apiKey;
return this;
}
@Override
public String toString() {
@ -963,9 +890,6 @@ public class SaTokenConfig implements Serializable {
+ ", sameTokenTimeout=" + sameTokenTimeout
+ ", checkSameToken=" + checkSameToken
+ ", cookie=" + cookie
+ ", sign=" + sign
+ ", signMany=" + signMany
+ ", apiKey=" + apiKey
+ "]";
}
@ -980,7 +904,7 @@ public class SaTokenConfig implements Serializable {
*/
@Deprecated
public long getActivityTimeout() {
System.err.println("配置项已过期请更换sa-token.activity-timeout -> sa-token.active-timeout");
// System.err.println("配置项已过期请更换sa-token.activity-timeout -> sa-token.active-timeout");
return activeTimeout;
}

View File

@ -201,7 +201,7 @@ public interface SaRequest {
* @return /
*/
default boolean isAjax() {
return getHeader("X-Requested-With") != null;
return "XMLHttpRequest".equalsIgnoreCase(getHeader("X-Requested-With")) || isParam("_ajax", "true");
}
/**

View File

@ -37,6 +37,9 @@ public interface SaErrorCode {
/** JSON 转换器未实现 */
int CODE_10003 = 10003;
/** HTTP 请求处理器未实现 */
int CODE_10004 = 10004;
/** 未能从全局 StpLogic 集合中找到对应 type 的 StpLogic */
int CODE_10011 = 10011;
@ -190,42 +193,6 @@ public interface SaErrorCode {
/** RSA 私钥解密异常 */
int CODE_12119 = 12119;
// ------------
/** 参与参数签名的秘钥不可为空 */
int CODE_12201 = 12201;
/** 给定的签名无效 */
int CODE_12202 = 12202;
/** timestamp 超出允许的范围 */
int CODE_12203 = 12203;
/** 未找到对应 appid 的 SaSignConfig */
int CODE_12211 = 12211;
// ------------
/** 无效 API Key */
int CODE_12301 = 12301;
/** API Key 已过期 */
int CODE_12302 = 12302;
/** API Key 已被禁用 */
int CODE_12303 = 12303;
/** API Key 字段自检未通过 */
int CODE_12304 = 12304;
/** 未开启索引记录功能却调用了相关 API */
int CODE_12305 = 12305;
/** API Key 不具有指定 Scope */
int CODE_12311 = 12311;
/** API Key 不属于指定用户 */
int CODE_12312 = 12312;
// ------------

View File

@ -148,36 +148,4 @@ public class SaTokenException extends RuntimeException {
}
}
// ------------------- 已过期 -------------------
/**
* 如果flag==true则抛出message异常
* <h2>已过期请使用 notTrue 代替用法不变</h2>
*
* @param flag 标记
* @param message 异常信息
* @param code 异常细分状态码
*/
@Deprecated
public static void throwBy(boolean flag, String message, int code) {
if(flag) {
throw new SaTokenException(message).setCode(code);
}
}
/**
* 如果value==null或者isEmpty则抛出message异常
* <h2>已过期请使用 notEmpty 代替用法不变</h2>
*
* @param value
* @param message 异常信息
* @param code 异常细分状态码
*/
@Deprecated
public static void throwByNull(Object value, String message, int code) {
if(SaFoxUtil.isEmpty(value)) {
throw new SaTokenException(message).setCode(code);
}
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.http;
import java.util.Map;
/**
* Http 请求处理器
*
* @author click33
* @since 1.43.0
*/
public interface SaHttpTemplate {
/**
* get 请求
*
* @param url /
* @return /
*/
String get(String url);
/**
* post 请求form-data 格式参数
*
* @param url /
* @param params /
* @return /
*/
String postByFormData(String url, Map<String, Object> params);
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.http;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.NotImplException;
import java.util.Map;
/**
* Http 请求处理器默认实现类
*
* @author click33
* @since 1.43.0
*/
public class SaHttpTemplateDefaultImpl implements SaHttpTemplate {
public static final String ERROR_MESSAGE = "HTTP 请求处理器未实现";
/**
* get 请求
*
* @param url /
* @return /
*/
@Override
public String get(String url) {
throw new NotImplException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10004);
}
/**
* post 请求form-data 格式参数
*/
@Override
public String postByFormData(String url, Map<String, Object> params) {
throw new NotImplException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10004);
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.http;
import cn.dev33.satoken.SaManager;
import java.util.Map;
/**
* Http 请求处理器 工具类
*
* @author click33
* @since 1.43.0
*/
public class SaHttpUtil {
/**
* get 请求
*
* @param url /
* @return /
*/
public static String get(String url) {
return SaManager.getSaHttpTemplate().get(url);
}
/**
* post 请求form-data 格式参数
*
* @param url /
* @param params /
* @return /
*/
public static String postByFormData(String url, Map<String, Object> params) {
return SaManager.getSaHttpTemplate().postByFormData(url, params);
}
}

View File

@ -121,6 +121,11 @@ public class SaHttpDigestTemplate {
if (kv.length == 2) {
map.put(kv[0].trim(), kv[1].trim().replace("\"", ""));
}
// 兼容字符串包含多个=的情况uri 带参数的问题
// username="sa", realm="Sa-Token", nonce="IWlEwO23oCAbIAbHX1BYnX5ddKHUdsjW", uri="/test/testDigest?name=zhangsan&age=18", response="c4359210ccb23c985234ee6e02def88d", opaque="H6jPyjwfioc0oUbDE0OSmpX7wznfxxMo", qop=auth, nc=00000002, cnonce="46dd0073c981a9c7"
else if (s.contains("=")) {
map.put(kv[0].trim(), s.substring(kv[0].length() + 1).trim().replace("\"", ""));
}
}
/*

View File

@ -265,15 +265,16 @@ public class SaTokenEventCenter {
}
/**
* 事件发布指定 Token 续期成功
*
* @param tokenValue token
* @param loginId 账号id
* @param timeout 续期时间
* 每次 Token 续期时触发注意 timeout 续期而不是 active-timeout 续期
*
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue token
* @param timeout 续期时间
*/
public static void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
public static void doRenewTimeout(String loginType, Object loginId, String tokenValue, long timeout) {
for (SaTokenListener listener : listenerList) {
listener.doRenewTimeout(tokenValue, loginId, timeout);
listener.doRenewTimeout(loginType, loginId, tokenValue, timeout);
}
}

View File

@ -112,12 +112,13 @@ public interface SaTokenListener {
/**
* 每次 Token 续期时触发注意 timeout 续期而不是 active-timeout 续期
*
* @param tokenValue token
* @param loginId 账号id
*
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue token
* @param timeout 续期时间
*/
void doRenewTimeout(String tokenValue, Object loginId, long timeout);
void doRenewTimeout(String loginType, Object loginId, String tokenValue, long timeout);
/**
* 全局组件载入

View File

@ -17,8 +17,8 @@ package cn.dev33.satoken.listener;
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.util.SaFoxUtil;
import static cn.dev33.satoken.SaManager.log;
@ -112,14 +112,13 @@ public class SaTokenListenerForLog implements SaTokenListener {
}
/**
* 每次Token续期时触发
* 每次 Token 续期时触发
*/
@Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
public void doRenewTimeout(String loginType, Object loginId, String tokenValue, long timeout) {
log.info("token 续期成功, {} 秒后到期, 帐号={}, token值={} ", timeout, loginId, tokenValue);
}
/**
* 全局组件载入
* @param compName 组件名称

View File

@ -78,7 +78,7 @@ public class SaTokenListenerForSimple implements SaTokenListener {
}
@Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
public void doRenewTimeout(String loginType, Object loginId, String tokenValue, long timeout) {
}

View File

@ -151,6 +151,18 @@ public class SaTotpTemplate {
return StrFormatter.format("otpauth://totp/{}?secret={}", account, secretKey);
}
/**
* 生成谷歌认证器的扫码字符串 (形如otpauth://totp/{issuer}:{account}?secret={secretKey}&issuer={issuer})
*
* @param account 账户名
* @param issuer 签发者
* @param secretKey TOTP 秘钥
* @return /
*/
public String generateGoogleSecretKey(String account, String issuer, String secretKey) {
return StrFormatter.format("otpauth://totp/{}:{}?secret={}&issuer={}", issuer, account, secretKey, issuer);
}
protected String _generateTOTP(String secretKey, long time) {
// Base32解码密钥
byte[] keyBytes = SaBase32Util.decodeStringToBytes(secretKey);

View File

@ -88,4 +88,16 @@ public class SaTotpUtil {
return SaManager.getSaTotpTemplate().generateGoogleSecretKey(account, secretKey);
}
/**
* 生成谷歌认证器的扫码字符串 (形如otpauth://totp/{issuer}:{account}?secret={secretKey}&issuer={issuer})
*
* @param account 账户名
* @param issuer 签发者
* @param secretKey TOTP 秘钥
* @return /
*/
public static String generateGoogleSecretKey(String account, String issuer, String secretKey) {
return SaManager.getSaTotpTemplate().generateGoogleSecretKey(account, issuer, secretKey);
}
}

View File

@ -916,8 +916,16 @@ public class StpLogic {
if(session != null) {
// 2遍历此 SaTerminalInfo 客户端列表清除相关数据
List<SaTerminalInfo> terminalList = session.getTerminalListByDeviceType(logoutParameter.getDeviceType());
List<SaTerminalInfo> terminalList = session.terminalListCopy();
for (SaTerminalInfo terminal: terminalList) {
// 不符合 deviceType 的跳过
if( ! SaFoxUtil.isEmpty(logoutParameter.getDeviceType()) && ! logoutParameter.getDeviceType().equals(terminal.getDeviceType())) {
continue;
}
// 不符合 deviceId 的跳过
if( ! SaFoxUtil.isEmpty(logoutParameter.getDeviceId()) && ! logoutParameter.getDeviceId().equals(terminal.getDeviceId())) {
continue;
}
_removeTerminal(session, terminal, logoutParameter);
}
@ -1994,7 +2002,7 @@ public class StpLogic {
}
// 7$$ 发布事件某某 token 被续期了
SaTokenEventCenter.doRenewTimeout(tokenValue, loginId, timeout);
SaTokenEventCenter.doRenewTimeout(loginType, loginId, tokenValue, timeout);
}
@ -2380,6 +2388,56 @@ public class StpLogic {
session.forEachTerminalList(function);
}
/**
* 返回当前 token 指向的 SaTerminalInfo 设备信息如果 token 无效则返回 null
*
* @return /
*/
public SaTerminalInfo getTerminalInfo() {
return getTerminalInfoByToken(getTokenValue());
}
/**
* 返回指定 token 指向的 SaTerminalInfo 设备信息如果 Token 无效则返回 null
*
* @param tokenValue 指定 token
* @return /
*/
public SaTerminalInfo getTerminalInfoByToken(String tokenValue) {
// 1如果 token null直接提前返回
if(SaFoxUtil.isEmpty(tokenValue)) {
return null;
}
// 2判断 Token 是否有效
Object loginId = getLoginIdNotHandle(tokenValue);
if( ! isValidLoginId(loginId)) {
return null;
}
// 3判断 Account-Session 是否存在
SaSession session = getSessionByLoginId(loginId, false);
if(session == null) {
return null;
}
// 4判断 Token 是否已被冻结
if(isFreeze(tokenValue)) {
return null;
}
// 5遍历 Account-Session 上的客户端 token 列表寻找当前 token 对应的设备类型
List<SaTerminalInfo> terminalList = session.terminalListCopy();
for (SaTerminalInfo terminal : terminalList) {
if(terminal.getTokenValue().equals(tokenValue)) {
return terminal;
}
}
// 6没有找到还是返回 null
return null;
}
/**
* 返回当前会话的登录设备类型
*
@ -2396,38 +2454,28 @@ public class StpLogic {
* @return 当前令牌的登录设备类型
*/
public String getLoginDeviceTypeByToken(String tokenValue) {
// 1如果 token null直接提前返回
if(SaFoxUtil.isEmpty(tokenValue)) {
return null;
}
SaTerminalInfo terminalInfo = getTerminalInfoByToken(tokenValue);
return terminalInfo == null ? null : terminalInfo.getDeviceType();
}
// 2获取此 token 对应的 loginId如果为null或者此token已被冻结直接返回null
Object loginId = getLoginIdNotHandle(tokenValue);
if( ! isValidLoginId(loginId)) {
return null;
}
if(getTokenActiveTimeoutByToken(tokenValue) == SaTokenDao.NOT_VALUE_EXPIRE ) {
return null;
}
/**
* 返回当前会话的登录设备 ID
*
* @return /
*/
public String getLoginDeviceId() {
return getLoginDeviceIdByToken(getTokenValue());
}
// 3获取这个账号的 Account-Session
SaSession session = getSessionByLoginId(loginId, false);
// 4 null 说明尚未登录当然也就不存在什么设备类型直接返回 null
if(session == null) {
return null;
}
// 5遍历 Account-Session 上的客户端 token 列表寻找当前 token 对应的设备类型
List<SaTerminalInfo> terminalList = session.terminalListCopy();
for (SaTerminalInfo terminal : terminalList) {
if(terminal.getTokenValue().equals(tokenValue)) {
return terminal.getDeviceType();
}
}
// 6没有找到还是返回 null
return null;
/**
* 返回指定 token 会话的登录设备 ID
*
* @param tokenValue 指定token
* @return /
*/
public String getLoginDeviceIdByToken(String tokenValue) {
SaTerminalInfo terminalInfo = getTerminalInfoByToken(tokenValue);
return terminalInfo == null ? null : terminalInfo.getDeviceId();
}
/**

View File

@ -678,6 +678,15 @@ public class StpUtil {
stpLogic.checkActiveTimeout();
}
/**
* 获取当前 token 的最后活跃时间13位时间戳如果不存在则返回 -2
*
* @return /
*/
public static long getTokenLastActiveTime() {
return stpLogic.getTokenLastActiveTime();
}
// ------------------- 过期时间相关 -------------------
@ -1010,6 +1019,25 @@ public class StpUtil {
stpLogic.forEachTerminalList(loginId, function);
}
/**
* 返回当前 token 指向的 SaTerminalInfo 设备信息如果 token 无效则返回 null
*
* @return /
*/
public static SaTerminalInfo getTerminalInfo() {
return stpLogic.getTerminalInfo();
}
/**
* 返回指定 token 指向的 SaTerminalInfo 设备信息如果 Token 无效则返回 null
*
* @param tokenValue 指定 token
* @return /
*/
public static SaTerminalInfo getTerminalInfoByToken(String tokenValue) {
return stpLogic.getTerminalInfoByToken(tokenValue);
}
/**
* 返回当前会话的登录设备类型
*
@ -1030,12 +1058,22 @@ public class StpUtil {
}
/**
* 获取当前 token 的最后活跃时间13位时间戳如果不存在则返回 -2
* 返回当前会话的登录设备 ID
*
* @return /
*/
public static long getTokenLastActiveTime() {
return stpLogic.getTokenLastActiveTime();
public static String getLoginDeviceId() {
return stpLogic.getLoginDeviceId();
}
/**
* 返回指定 token 会话的登录设备 ID
*
* @param tokenValue 指定token
* @return /
*/
public static String getLoginDeviceIdByToken(String tokenValue) {
return stpLogic.getLoginDeviceIdByToken(tokenValue);
}
/**

View File

@ -36,10 +36,17 @@ public class SaLogoutParameter {
// --------- 单独参数
/**
* 需要注销的设备类型 (如果不指定则默认注销所有客户端)
* 需要注销的设备类型 ( null 代表不限制为具体值代表只注销此设备类型的会话)
* <br/> (此参数只在调用 StpUtil.logout(id, parame) 时有效)
*/
private String deviceType;
/**
* 需要注销的设备ID ( null 代表不限制为具体值代表只注销此设备ID的会话)
* <br/> (此参数只在调用 StpUtil.logout(id, param) 时有效)
*/
private String deviceId;
/**
* 注销类型 (LOGOUT=注销下线KICKOUT=踢人下线REPLACED=顶人下线)
*/
@ -50,13 +57,13 @@ public class SaLogoutParameter {
/**
* 注销范围 (TOKEN=只注销当前 token 的会话ACCOUNT=注销当前 token 指向的 loginId 其所有客户端会话)
* <br/> (此参数只在调用 StpUtil.logout() 时有效)
* <br/> (此参数只在调用 StpUtil.logout(param) 时有效)
*/
private SaLogoutRange range;
/**
* 如果 token 已被冻结是否保留其操作权 (是否允许此 token 调用注销API)
* <br/> (此参数只在调用 StpUtil.[logout/kickout/replaced]ByTokenValue("token") 时有效)
* <br/> (此参数只在调用 StpUtil.[logout/kickout/replaced]ByTokenValue("token", param) 时有效)
*/
private Boolean isKeepFreezeOps;
@ -119,7 +126,7 @@ public class SaLogoutParameter {
/**
* 获取 如果 token 已被冻结是否保留其操作权 (是否允许此 token 调用注销API)
* <br/> (此参数只在调用 StpUtil.[logout/kickout/replaced]ByTokenValue("token") 时有效)
* <br/> (此参数只在调用 StpUtil.[logout/kickout/replaced]ByTokenValue("token", param) 时有效)
*
* @return /
*/
@ -129,7 +136,7 @@ public class SaLogoutParameter {
/**
* 设置 如果 token 已被冻结是否保留其操作权 (是否允许此 token 调用注销API)
* <br/> (此参数只在调用 StpUtil.[logout/kickout/replaced]ByTokenValue("token") 时有效)
* <br/> (此参数只在调用 StpUtil.[logout/kickout/replaced]ByTokenValue("token", param) 时有效)
*
* @param isKeepFreezeOps /
* @return 对象自身
@ -140,7 +147,8 @@ public class SaLogoutParameter {
}
/**
* 需要注销的设备类型 (如果不指定则默认注销所有客户端)
* 需要注销的设备类型 ( null 代表不限制为具体值代表只注销此设备类型的会话)
* <br/> (此参数只在调用 StpUtil.logout(id, parame) 时有效)
*
* @return deviceType /
*/
@ -149,7 +157,8 @@ public class SaLogoutParameter {
}
/**
* 需要注销的设备类型 (如果不指定则默认注销所有客户端)
* 需要注销的设备类型 ( null 代表不限制为具体值代表只注销此设备类型的会话)
* <br/> (此参数只在调用 StpUtil.logout(id, parame) 时有效)
*
* @param deviceType /
* @return /
@ -159,6 +168,28 @@ public class SaLogoutParameter {
return this;
}
/**
* 需要注销的设备ID ( null 代表不限制为具体值代表只注销此设备 ID 的会话)
* <br/> (此参数只在调用 StpUtil.logout(id, parame) 时有效)
*
* @return /
*/
public String getDeviceId() {
return this.deviceId;
}
/**
* 需要注销的设备类型 ( null 代表不限制为具体值代表只注销此设备 ID 的会话)
* <br/> (此参数只在调用 StpUtil.logout(id, parame) 时有效)
*
* @param deviceId /
* @return /
*/
public SaLogoutParameter setDeviceId(String deviceId) {
this.deviceId = deviceId;
return this;
}
/**
* 注销类型 (LOGOUT=注销下线KICKOUT=踢人下线REPLACED=顶人下线)
*
@ -181,7 +212,7 @@ public class SaLogoutParameter {
/**
* 注销范围 (TOKEN=只注销当前 token 的会话ACCOUNT=注销当前 token 指向的 loginId 其所有客户端会话)
* <br/> (此参数只在调用 StpUtil.logout() 时有效)
* <br/> (此参数只在调用 StpUtil.logout(param) 时有效)
*
* @return /
*/
@ -191,7 +222,7 @@ public class SaLogoutParameter {
/**
* 注销范围 (TOKEN=只注销当前 token 的会话ACCOUNT=注销当前 token 指向的 loginId 其所有客户端会话)
* <br/> (此参数只在调用 StpUtil.logout() 时有效)
* <br/> (此参数只在调用 StpUtil.logout(param) 时有效)
*
* @param range /
* @return /
@ -208,6 +239,7 @@ public class SaLogoutParameter {
public String toString() {
return "SaLoginParameter ["
+ "deviceType=" + deviceType
+ ", deviceId=" + deviceId
+ ", isKeepTokenSession=" + isKeepTokenSession
+ ", isKeepFreezeOps=" + isKeepFreezeOps
+ ", mode=" + mode

View File

@ -17,15 +17,12 @@ package cn.dev33.satoken.strategy;
import cn.dev33.satoken.annotation.*;
import cn.dev33.satoken.annotation.handler.*;
import cn.dev33.satoken.fun.strategy.SaCheckELRootMapExtendFunction;
import cn.dev33.satoken.fun.strategy.SaCheckMethodAnnotationFunction;
import cn.dev33.satoken.fun.strategy.SaGetAnnotationFunction;
import cn.dev33.satoken.fun.strategy.SaIsAnnotationPresentFunction;
import cn.dev33.satoken.fun.strategy.*;
import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.router.SaRouter;
import java.lang.annotation.Annotation;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.*;
/**
* Sa-Token 注解鉴权相关策略
@ -56,7 +53,6 @@ public final class SaAnnotationStrategy {
* 注册所有默认的注解处理器
*/
public void registerDefaultAnnotationHandler() {
annotationHandlerMap.put(SaIgnore.class, new SaIgnoreHandler());
annotationHandlerMap.put(SaCheckLogin.class, new SaCheckLoginHandler());
annotationHandlerMap.put(SaCheckRole.class, new SaCheckRoleHandler());
annotationHandlerMap.put(SaCheckPermission.class, new SaCheckPermissionHandler());
@ -65,8 +61,6 @@ public final class SaAnnotationStrategy {
annotationHandlerMap.put(SaCheckHttpBasic.class, new SaCheckHttpBasicHandler());
annotationHandlerMap.put(SaCheckHttpDigest.class, new SaCheckHttpDigestHandler());
annotationHandlerMap.put(SaCheckOr.class, new SaCheckOrHandler());
annotationHandlerMap.put(SaCheckSign.class, new SaCheckSignHandler());
annotationHandlerMap.put(SaCheckApiKey.class, new SaCheckApiKeyHandler());
}
/**
@ -98,21 +92,42 @@ public final class SaAnnotationStrategy {
/**
* 对一个 [Method] 对象进行注解校验 注解鉴权内部实现
*/
@SuppressWarnings("unchecked")
public SaCheckMethodAnnotationFunction checkMethodAnnotation = (method) -> {
// 遍历所有的注解处理器检查此 method 是否具有这些指定的注解
// 如果 Method 或其所属 Class 上有 @SaIgnore 注解则直接跳过整个校验过程
if(instance.isAnnotationPresent.apply(method, SaIgnore.class)) {
SaRouter.stop();
}
// 先校验 Method 所属 Class 上的注解
instance.checkElementAnnotation.accept(method.getDeclaringClass());
// 再校验 Method 上的注解
instance.checkElementAnnotation.accept(method);
};
/**
* 对一个 [Element] 对象进行注解校验 注解鉴权内部实现
*/
@SuppressWarnings("unchecked")
public SaCheckElementAnnotationFunction checkElementAnnotation = (element) -> {
// 如果此元素上标注了 @SaCheckOr则必须在后续判断中忽略掉其指定的 append() 类型注解判断
List<Class<? extends Annotation>> ignoreClassList = new ArrayList<>();
SaCheckOr checkOr = (SaCheckOr)instance.getAnnotation.apply(element, SaCheckOr.class);
if(checkOr != null) {
ignoreClassList = Arrays.asList(checkOr.append());
}
// 遍历所有的注解处理器检查此 element 是否具有这些指定的注解
for (Map.Entry<Class<?>, SaAnnotationHandlerInterface<?>> entry: annotationHandlerMap.entrySet()) {
// 先校验 Method 所属 Class 上的注解
Annotation classTakeAnnotation = instance.getAnnotation.apply(method.getDeclaringClass(), (Class<Annotation>)entry.getKey());
if(classTakeAnnotation != null) {
entry.getValue().check(classTakeAnnotation, method);
// 忽略掉在 @SaCheckOr append 字段指定的注解
Class<Annotation> atClass = (Class<Annotation>)entry.getKey();
if(ignoreClassList.contains(atClass)) {
continue;
}
// 再校验 Method 上的注解
Annotation methodTakeAnnotation = instance.getAnnotation.apply(method, (Class<Annotation>)entry.getKey());
if(methodTakeAnnotation != null) {
entry.getValue().check(methodTakeAnnotation, method);
Annotation annotation = instance.getAnnotation.apply(element, atClass);
if(annotation != null) {
entry.getValue().check(annotation, element);
}
}
};
@ -121,7 +136,6 @@ public final class SaAnnotationStrategy {
* 从元素上获取注解
*/
public SaGetAnnotationFunction getAnnotation = (element, annotationClass)->{
// 默认使用jdk的注解处理器
return element.getAnnotation(annotationClass);
};

View File

@ -22,6 +22,7 @@ import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.raw.SaRawSessionDelegator;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaTtlMethods;
import java.util.*;
@ -35,7 +36,7 @@ import java.util.*;
* @author click33
* @since 1.42.0
*/
public class SaTempTemplate {
public class SaTempTemplate implements SaTtlMethods {
/**
*默认命名空间
@ -256,14 +257,14 @@ public class SaTempTemplate {
if(session == null) {
session = rawSessionDelegator.getSessionById(value, false);
if(session == null) {
return newTempTokenMap();
return newTokenIndexMap();
}
}
// 重新整理索引列表
Map<String, Long> tempTokenNewList = newTempTokenMap();
Map<String, Long> tempTokenNewList = newTokenIndexMap();
ArrayList<Long> tempTokenTtlList = new ArrayList<>();
Map<String, Long> tempTokenMap = session.get(TEMP_TOKEN_MAP, this::newTempTokenMap);
Map<String, Long> tempTokenMap = session.get(TEMP_TOKEN_MAP, this::newTokenIndexMap);
for (Map.Entry<String, Long> entry : tempTokenMap.entrySet()) {
long ttl = expireTimeToTtl(entry.getValue());
if(ttl != SaTokenDao.NOT_VALUE_EXPIRE) {
@ -306,7 +307,7 @@ public class SaTempTemplate {
* @param timeout /
*/
protected void addTempTokenIndex(SaSession session, String token, long timeout) {
Map<String, Long> tempTokenMap = session.get(TEMP_TOKEN_MAP, this::newTempTokenMap);
Map<String, Long> tempTokenMap = session.get(TEMP_TOKEN_MAP, this::newTokenIndexMap);
if(! tempTokenMap.containsKey(token)) {
tempTokenMap.put(token, ttlToExpireTime(timeout));
session.set(TEMP_TOKEN_MAP, tempTokenMap);
@ -319,21 +320,13 @@ public class SaTempTemplate {
* @param token /
*/
protected void deleteTempTokenIndex(SaSession session, String token) {
Map<String, Long> tempTokenMap = session.get(TEMP_TOKEN_MAP, this::newTempTokenMap);
Map<String, Long> tempTokenMap = session.get(TEMP_TOKEN_MAP, this::newTokenIndexMap);
if(tempTokenMap.containsKey(token)) {
tempTokenMap.remove(token);
session.set(TEMP_TOKEN_MAP, tempTokenMap);
}
}
/**
* 获取一个新的 TempTokenMap 集合
* @return /
*/
protected Map<String, Long> newTempTokenMap() {
return new LinkedHashMap<>();
}
// -------- 元操作
@ -364,55 +357,6 @@ public class SaTempTemplate {
}
}
/**
* 过期时间转 ttl () 获取最大 ttl
* @param tempTokenTtlList /
* @return /
*/
protected long getMaxTtl(ArrayList<Long> tempTokenTtlList) {
long maxTtl = 0;
for (long ttl : tempTokenTtlList) {
if(ttl == SaTokenDao.NEVER_EXPIRE) {
maxTtl = SaTokenDao.NEVER_EXPIRE;
break;
}
if(ttl > maxTtl) {
maxTtl = ttl;
}
}
return maxTtl;
}
/**
* 过期时间转 ttl ()
* @param expireTime /
* @return /
*/
protected long expireTimeToTtl(long expireTime) {
if(expireTime == SaTokenDao.NEVER_EXPIRE) {
return SaTokenDao.NEVER_EXPIRE;
}
if(expireTime == SaTokenDao.NOT_VALUE_EXPIRE) {
return SaTokenDao.NOT_VALUE_EXPIRE;
}
return (expireTime - System.currentTimeMillis()) / 1000;
}
/**
* ttl () 过期时间
* @param ttl /
* @return /
*/
protected long ttlToExpireTime(long ttl) {
if(ttl == SaTokenDao.NEVER_EXPIRE) {
return SaTokenDao.NEVER_EXPIRE;
}
if(ttl == SaTokenDao.NOT_VALUE_EXPIRE) {
return SaTokenDao.NOT_VALUE_EXPIRE;
}
return ttl * 1000 + System.currentTimeMillis();
}
/**
* 获取在存储临时 token 数据时应该使用的 key
* @param token token值

View File

@ -41,7 +41,9 @@ public class SaResult extends LinkedHashMap<String, Object> implements Serializa
// 预定的状态码
public static final int CODE_SUCCESS = 200;
public static final int CODE_ERROR = 500;
public static final int CODE_ERROR = 500;
public static final int CODE_NOT_PERMISSION = 403;
public static final int CODE_NOT_LOGIN = 401;
/**
* 构建
@ -147,8 +149,10 @@ public class SaResult extends LinkedHashMap<String, Object> implements Serializa
* @return 对象自身
*/
public SaResult setMap(Map<String, ?> map) {
for (String key : map.keySet()) {
this.put(key, map.get(key));
if(map != null) {
for (String key : map.keySet()) {
this.put(key, map.get(key));
}
}
return this;
}
@ -213,6 +217,18 @@ public class SaResult extends LinkedHashMap<String, Object> implements Serializa
return new SaResult(CODE_ERROR, msg, null);
}
// 构建未登录
public static SaResult notLogin() {
return new SaResult(CODE_NOT_LOGIN, "not login", null);
}
// 构建无权限
public static SaResult notPermission() {
return new SaResult(CODE_NOT_PERMISSION, "not permission", null);
}
// 构建指定状态码
public static SaResult get(int code, String msg, Object data) {
return new SaResult(code, msg, data);

View File

@ -0,0 +1,64 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.util;
import cn.dev33.satoken.fun.SaFunction;
import java.util.function.Supplier;
/**
* 代码语法糖封装
*
* @author click33
* @since 1.43.0
*/
public class SaSugar {
/**
* 执行一个 Lambda 表达式返回这个 Lambda 表达式的结果值
* <br> 方便组织代码例如:
* <pre>
int value = Sugar.get(() -> {
int a = 1;
int b = 2;
return a + b;
});
</pre>
* @param <R> 返回值类型
* @param lambda lambda 表达式
* @return lambda 的执行结果
*/
public static <R> R get(Supplier<R> lambda) {
return lambda.get();
}
/**
* 执行一个 Lambda 表达式
* <br> 方便组织代码例如:
* <pre>
Sugar.exe(() -> {
int a = 1;
int b = 2;
return a + b;
});
</pre>
* @param lambda lambda 表达式
*/
public static void exe(SaFunction lambda) {
lambda.run();
}
}

View File

@ -36,7 +36,7 @@ public class SaTokenConsts {
/**
* Sa-Token 当前版本号
*/
public static final String VERSION_NO = "v1.42.0";
public static final String VERSION_NO = "v1.44.0";
/**
* Sa-Token 开源地址 Gitee

View File

@ -0,0 +1,119 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.util;
import cn.dev33.satoken.dao.SaTokenDao;
import java.util.*;
/**
* TTL 操作工具方法
*
* @author click33
* @since 1.43.0
*/
public interface SaTtlMethods {
/**
* 获取一个新的 Token 集合
* @return /
*/
default List<String> newTokenValueList() {
return new ArrayList<>();
}
/**
* 获取一个新的 TokenIndexMap 集合
* @return /
*/
default Map<String, Long> newTokenIndexMap() {
return new LinkedHashMap<>();
}
/**
* 获取最大 ttl
* @param ttlList /
* @return /
*/
default long getMaxTtl(ArrayList<Long> ttlList) {
long maxTtl = 0;
for (long ttl : ttlList) {
if(ttl == SaTokenDao.NEVER_EXPIRE) {
maxTtl = SaTokenDao.NEVER_EXPIRE;
break;
}
if(ttl > maxTtl) {
maxTtl = ttl;
}
}
return maxTtl;
}
/**
* 获取最大 ttl 过期时间 (13位时间戳) ttl ()
* @param expireTimeList /
* @return /
*/
default long getMaxTtlByExpireTime(Collection<Long> expireTimeList) {
long maxTtl = 0;
for (long expireTime : expireTimeList) {
long ttl = expireTimeToTtl(expireTime);
if(ttl == SaTokenDao.NEVER_EXPIRE) {
maxTtl = SaTokenDao.NEVER_EXPIRE;
break;
}
if(ttl > maxTtl) {
maxTtl = ttl;
}
}
return maxTtl;
}
/**
* 过期时间 (13位时间戳) (13位时间戳) ttl ()
* @param expireTime /
* @return /
*/
default long expireTimeToTtl(long expireTime) {
if(expireTime == SaTokenDao.NEVER_EXPIRE) {
return SaTokenDao.NEVER_EXPIRE;
}
if(expireTime == SaTokenDao.NOT_VALUE_EXPIRE) {
return SaTokenDao.NOT_VALUE_EXPIRE;
}
long currentTime = System.currentTimeMillis();
if(expireTime < currentTime) {
return SaTokenDao.NOT_VALUE_EXPIRE;
}
return (expireTime - currentTime) / 1000;
}
/**
* ttl () 过期时间 (13位时间戳)
* @param ttl /
* @return /
*/
default long ttlToExpireTime(long ttl) {
if(ttl == SaTokenDao.NEVER_EXPIRE) {
return SaTokenDao.NEVER_EXPIRE;
}
if(ttl < 0) {
return SaTokenDao.NOT_VALUE_EXPIRE;
}
return ttl * 1000 + System.currentTimeMillis();
}
}

View File

@ -38,13 +38,15 @@
<module>sa-token-demo-springboot-low-version</module>
<module>sa-token-demo-springboot-redis</module>
<module>sa-token-demo-springboot-redisson</module>
<module>sa-token-demo-sse</module>
<module>sa-token-demo-ssm</module>
<module>sa-token-demo-sso/sa-token-demo-sso-server</module>
<module>sa-token-demo-sso/sa-token-demo-sso1-client</module>
<module>sa-token-demo-sso/sa-token-demo-sso2-client</module>
<module>sa-token-demo-sso/sa-token-demo-sso3-client</module>
<module>sa-token-demo-sso/sa-token-demo-sso3-client-test2</module>
<module>sa-token-demo-sso/sa-token-demo-sso3-client-nosdk</module>
<module>sa-token-demo-sso/sa-token-demo-sso3-client-resdk</module>
<module>sa-token-demo-sso/sa-token-demo-sso3-client-anon</module>
<module>sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon</module>
<module>sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon</module>
<module>sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon</module>
@ -55,8 +57,9 @@
<module>sa-token-demo-webflux-springboot3</module>
<module>sa-token-demo-websocket</module>
<module>sa-token-demo-websocket-spring</module>
<module>sa-token-demo-loveqq-boot</module>
</modules>
</modules>

View File

@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>
@ -47,6 +47,13 @@
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- Sa-Token 整合 API Key -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-apikey</artifactId>
<version>${sa-token.version}</version>
</dependency>
<!-- 热刷新 -->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -1,6 +1,7 @@
package com.pj;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.apikey.SaApiKeyManager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@ -9,8 +10,9 @@ public class SaTokenApiKeyApplication {
public static void main(String[] args) {
SpringApplication.run(SaTokenApiKeyApplication.class, args);
System.out.println("\n启动成功Sa-Token 配置如下:" + SaManager.getConfig());
System.out.println("\n测试访问http://localhost:8081/index.html");
System.out.println("启动成功Sa-Token 配置如下:" + SaManager.getConfig());
System.out.println("启动成功API Key 配置如下:" + SaApiKeyManager.getConfig());
System.out.println("测试访问http://localhost:8081/index.html");
}
}

View File

@ -1,7 +1,7 @@
package com.pj.test;
import cn.dev33.satoken.apikey.SaApiKeyUtil;
import cn.dev33.satoken.apikey.model.ApiKeyModel;
import cn.dev33.satoken.apikey.template.SaApiKeyUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.RequestMapping;

View File

@ -1,9 +1,9 @@
package com.pj.test;
import cn.dev33.satoken.annotation.SaCheckApiKey;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.apikey.SaApiKeyUtil;
import cn.dev33.satoken.apikey.annotation.SaCheckApiKey;
import cn.dev33.satoken.apikey.model.ApiKeyModel;
import cn.dev33.satoken.apikey.template.SaApiKeyUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

View File

@ -18,7 +18,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
<java.run.main.class>com.pj.SaTokenAsyncApplication</java.run.main.class>
</properties>

View File

@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>
@ -73,7 +73,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-bom</artifactId>
<version>1.42.0</version>
<version>1.44.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>

View File

@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -74,7 +74,7 @@ public class MySaTokenListener implements SaTokenListener {
/** 每次Token续期时触发 */
@Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
public void doRenewTimeout(String loginType, Object loginId, String tokenValue, long timeout) {
System.out.println("---------- 自定义侦听器实现 doRenewTimeout");
}

View File

@ -6,7 +6,7 @@ import cn.dev33.satoken.exception.SaTokenException;
import com.pj.satoken.custom_annotation.CheckAccount;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 CheckAccount 的处理器
@ -25,7 +25,7 @@ public class CheckAccountHandler implements SaAnnotationHandlerInterface<CheckAc
// 每次请求校验注解时会执行的方法
@Override
public void checkMethod(CheckAccount at, Method method) {
public void checkMethod(CheckAccount at, AnnotatedElement element) {
// 获取前端请求提交的参数
String name = SaHolder.getRequest().getParamNotNull("name");
String pwd = SaHolder.getRequest().getParamNotNull("pwd");

View File

@ -6,7 +6,7 @@ import com.pj.satoken.StpUserUtil;
import com.pj.satoken.custom_annotation.SaUserCheckLogin;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaUserCheckLogin 的处理器
@ -22,7 +22,7 @@ public class SaUserCheckLoginHandler implements SaAnnotationHandlerInterface<SaU
}
@Override
public void checkMethod(SaUserCheckLogin at, Method method) {
public void checkMethod(SaUserCheckLogin at, AnnotatedElement element) {
SaCheckLoginHandler._checkMethod(StpUserUtil.TYPE);
}

View File

@ -6,7 +6,7 @@ import com.pj.satoken.StpUserUtil;
import com.pj.satoken.custom_annotation.SaUserCheckPermission;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaUserCheckPermission 的处理器
@ -22,7 +22,7 @@ public class SaUserCheckPermissionHandler implements SaAnnotationHandlerInterfac
}
@Override
public void checkMethod(SaUserCheckPermission at, Method method) {
public void checkMethod(SaUserCheckPermission at, AnnotatedElement element) {
SaCheckPermissionHandler._checkMethod(StpUserUtil.TYPE, at.value(), at.mode(), at.orRole());
}

View File

@ -6,7 +6,7 @@ import com.pj.satoken.StpUserUtil;
import com.pj.satoken.custom_annotation.SaUserCheckRole;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaUserCheckRole 的处理器
@ -22,7 +22,7 @@ public class SaUserCheckRoleHandler implements SaAnnotationHandlerInterface<SaUs
}
@Override
public void checkMethod(SaUserCheckRole at, Method method) {
public void checkMethod(SaUserCheckRole at, AnnotatedElement element) {
SaCheckRoleHandler._checkMethod(StpUserUtil.TYPE, at.value(), at.mode());
}

View File

@ -6,7 +6,7 @@ import com.pj.satoken.StpUserUtil;
import com.pj.satoken.custom_annotation.SaUserCheckSafe;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.AnnotatedElement;
/**
* 注解 SaUserCheckPermission 的处理器
@ -22,7 +22,7 @@ public class SaUserCheckSafeHandler implements SaAnnotationHandlerInterface<SaUs
}
@Override
public void checkMethod(SaUserCheckSafe at, Method method) {
public void checkMethod(SaUserCheckSafe at, AnnotatedElement element) {
SaCheckSafeHandler._checkMethod(StpUserUtil.TYPE, at.value());
}

View File

@ -18,7 +18,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
<java.run.main.class>com.pj.SaTokenDeviceLockApplication</java.run.main.class>
</properties>

View File

@ -17,7 +17,7 @@
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
<dubbo.version>2.7.21</dubbo.version>
<nacos.version>1.4.2</nacos.version>
</properties>

View File

@ -17,7 +17,7 @@
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
<dubbo.version>2.7.21</dubbo.version>
<nacos.version>1.4.2</nacos.version>
</properties>

View File

@ -10,14 +10,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!--<version>2.3.1.RELEASE</version>-->
<version>2.5.15</version>
<!-- <version>2.5.15</version>-->
<version>3.4.3</version>
</parent>
<!-- 指定一些属性 -->
<properties>
<java.version>1.8</java.version>
<java.version>17</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
<dubbo.version>3.2.2</dubbo.version>
<nacos.version>2.2.2</nacos.version>
</properties>
@ -33,7 +34,7 @@
<!-- Sa-Token -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${sa-token.version}</version>
</dependency>

View File

@ -2,18 +2,19 @@ server:
# 端口号
port: 8081
spring:
# redis配置
redis:
# Redis数据库索引默认为0
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间
spring:
data:
# redis配置
redis:
# Redis数据库索引默认为0
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间
dubbo:
application:

View File

@ -10,14 +10,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!--<version>2.3.1.RELEASE</version>-->
<version>2.5.15</version>
<!-- <version>2.5.15</version>-->
<version>3.4.3</version>
</parent>
<!-- 指定一些属性 -->
<properties>
<java.version>1.8</java.version>
<java.version>17</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
<dubbo.version>3.2.2</dubbo.version>
<nacos.version>2.2.2</nacos.version>
</properties>
@ -33,7 +34,7 @@
<!-- Sa-Token -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${sa-token.version}</version>
</dependency>

View File

@ -14,9 +14,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Dubbo3ProviderApplication {
public static void main(String[] args) {
public static void main(String[] args) throws Exception {
SpringApplication.run(Dubbo3ProviderApplication.class, args);
System.out.println("Dubbo3ProviderApplication 启动成功");
}
}

View File

@ -9,9 +9,18 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Autowired
private DemoService demoService;
// 如果把 @Autowired 改为 @DubboReference
// 则可能在首次调用 dubbo 服务时控制台出现以下异常只打印异常信息不影响调用
// java.lang.reflect.InaccessibleObjectException: Unable to make field private byte java.lang.StackTraceElement.format accessible:
// module java.base does not "opens java.lang" to unnamed module @3a52dba3
//
// 在启动参数上加上如下即可解决
// --add-opens java.base/java.math=ALL-UNNAMED
@Autowired
public DemoService demoService;
// test
@RequestMapping("test")

View File

@ -2,19 +2,20 @@ server:
# 端口号
port: 8080
spring:
# redis配置
redis:
# Redis数据库索引默认为0
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间
timeout: 10s
spring:
data:
# redis配置
redis:
# Redis数据库索引默认为0
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间
timeout: 10s
# Dubbo
dubbo:

View File

@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -27,7 +27,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.10</lombok.version>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.kfyty</groupId>
<artifactId>loveqq-framework</artifactId>
<version>1.1.2</version>
<relativePath/>
</parent>
<artifactId>sa-token-demo-loveqq-boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<jdk.version>17</jdk.version>
<java.version>17</java.version>
<maven.source.version>17</maven.source.version>
<maven.compile.version>17</maven.compile.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>
<!-- 引导启动模块 -->
<dependency>
<groupId>com.kfyty</groupId>
<artifactId>loveqq-boot</artifactId>
<version>${loveqq.framework.version}</version>
</dependency>
<!-- reactor-netty 服务器,同时支持命令式/响应式编程范式 -->
<dependency>
<groupId>com.kfyty</groupId>
<artifactId>loveqq-boot-starter-netty</artifactId>
<version>${loveqq.framework.version}</version>
</dependency>
<!-- sa-token 集成 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-loveqq-boot-starter</artifactId>
<version>${sa-token.version}</version>
</dependency>
<!-- logback 启动器 -->
<dependency>
<groupId>com.kfyty</groupId>
<artifactId>loveqq-boot-starter-logback</artifactId>
<version>${loveqq.framework.version}</version>
</dependency>
<!-- yaml 支持,默认使用 properties 文件,如果使用 yaml 需自行引入依赖 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,21 @@
package com.pj;
import cn.dev33.satoken.SaManager;
import com.kfyty.loveqq.framework.boot.K;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.BootApplication;
import com.kfyty.loveqq.framework.web.core.autoconfig.annotation.EnableWebMvc;
/**
* Sa-Token 整合 loveqq-framework 示例
*
* @author kfyty725
*/
@EnableWebMvc
@BootApplication
public class SaTokenLoveqqApplication {
public static void main(String[] args) {
K.run(SaTokenLoveqqApplication.class, args);
System.out.println("\n启动成功Sa-Token配置如下" + SaManager.getConfig());
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.pj.satoken;
import cn.dev33.satoken.context.model.SaTokenContextModelBox;
import cn.dev33.satoken.loveqq.boot.utils.SaTokenContextUtil;
import cn.dev33.satoken.stp.StpUtil;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
import com.kfyty.loveqq.framework.web.core.filter.Filter;
import com.kfyty.loveqq.framework.web.core.filter.FilterChain;
import com.kfyty.loveqq.framework.web.core.http.ServerRequest;
import com.kfyty.loveqq.framework.web.core.http.ServerResponse;
/**
* 自定义过滤器
*/
@Component
public class MyFilter implements Filter {
/**
* 实现该方法可以实现 servlet/reactor 的统一
* 但是该方法内部是同步方法若需要异步可以实现仅 reactor 支持的 {@link Filter#doFilter(ServerRequest, ServerResponse, FilterChain)} 方法
*
* @param request 请求
* @param response 响应
*/
@Override
public Continue doFilter(ServerRequest request, ServerResponse response) {
System.out.println("进入自定义过滤器");
// set 上下文再调用 Sa-Token 同步 API并在 finally 里清除上下文
SaTokenContextModelBox prev = SaTokenContextUtil.setContext(request, response);
try {
System.out.println(StpUtil.isLogin());
} finally {
SaTokenContextUtil.clearContext(prev);
}
return Continue.TRUE;
}
}

View File

@ -0,0 +1,39 @@
package com.pj.satoken;
import cn.dev33.satoken.loveqq.boot.filter.SaRequestFilter;
import cn.dev33.satoken.util.SaResult;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Bean;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Configuration;
/**
* [Sa-Token 权限认证] 配置类
* @author click33
*
*/
@Configuration
public class SaTokenConfigure {
/**
* 注册 [sa-token全局过滤器]
*/
@Bean
public SaRequestFilter getSaReactorFilter() {
return new SaRequestFilter()
// 指定 [拦截路由]
.addInclude("/**")
// 指定 [放行路由]
.addExclude("/favicon.ico")
// 指定[认证函数]: 每次请求执行
.setAuth(r -> {
System.out.println("---------- sa全局认证");
// SaRouter.match("/test/test", () -> StpUtil.checkLogin());
})
// 指定[异常处理函数]每次[认证函数]发生异常时执行此函数
.setError(e -> {
System.out.println("---------- sa全局异常 ");
e.printStackTrace();
return SaResult.error(e.getMessage());
})
;
}
}

View File

@ -0,0 +1,42 @@
package com.pj.satoken;
import cn.dev33.satoken.stp.StpInterface;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义权限验证接口扩展
*/
@Component // 打开此注解保证此类被springboot扫描即可完成sa-token的自定义权限验证扩展
public class StpInterfaceImpl implements StpInterface {
/**
* 返回一个账号所拥有的权限码集合
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 本list仅做模拟实际项目中要根据具体业务逻辑来查询权限
List<String> list = new ArrayList<String>();
list.add("101");
list.add("user-add");
list.add("user-delete");
list.add("user-update");
list.add("user-get");
list.add("article-get");
return list;
}
/**
* 返回一个账号所拥有的角色标识集合
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// 本list仅做模拟实际项目中要根据具体业务逻辑来查询角色
List<String> list = new ArrayList<String>();
list.add("admin");
list.add("super-admin");
return list;
}
}

View File

@ -0,0 +1,18 @@
package com.pj.test;
import cn.dev33.satoken.util.SaResult;
import com.kfyty.loveqq.framework.web.core.annotation.ExceptionHandler;
import com.kfyty.loveqq.framework.web.core.annotation.RestControllerAdvice;
/**
* 全局异常处理
*/
@RestControllerAdvice
public class GlobalException {
@ExceptionHandler
public SaResult handlerException(Exception e) {
e.printStackTrace();
return SaResult.error(e.getMessage());
}
}

View File

@ -0,0 +1,116 @@
package com.pj.test;
import cn.dev33.satoken.loveqq.boot.context.SaReactorHolder;
import cn.dev33.satoken.loveqq.boot.utils.SaTokenContextUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired;
import com.kfyty.loveqq.framework.web.core.annotation.GetMapping;
import com.kfyty.loveqq.framework.web.core.annotation.RequestMapping;
import com.kfyty.loveqq.framework.web.core.annotation.RestController;
import com.kfyty.loveqq.framework.web.core.annotation.bind.CookieValue;
import com.kfyty.loveqq.framework.web.core.annotation.bind.RequestParam;
import com.kfyty.loveqq.framework.web.core.http.ServerRequest;
import com.kfyty.loveqq.framework.web.core.http.ServerResponse;
import reactor.core.publisher.Mono;
import java.time.Duration;
/**
* 测试专用 Controller
* 本示例是基于 reactor 编写如果是 servlet去除 SaReactorHolder/SaTokenContextUtil 包装直接调用 sa-token api 即可
*
* @author click33
*/
@RestController
@RequestMapping("/test/")
public class TestController {
@Autowired
UserService userService;
// 登录测试Controller 里调用 Sa-Token API --- http://localhost:8081/test/login
@GetMapping("login")
public Mono<SaResult> login(@RequestParam(defaultValue = "10001") String id) {
return SaReactorHolder.sync(() -> {
StpUtil.login(id);
return SaResult.ok("登录成功");
});
}
// API测试手动设置上下文try-finally 形式 --- http://localhost:8081/test/isLogin
@GetMapping("isLogin")
public SaResult isLogin(ServerRequest request, ServerResponse response) {
try {
SaTokenContextUtil.setContext(request, response);
System.out.println("是否登录:" + StpUtil.isLogin());
return SaResult.data(StpUtil.getTokenInfo());
} finally {
SaTokenContextUtil.clearContext(null);
}
}
// API测试手动设置上下文lambda 表达式形式 --- http://localhost:8081/test/isLogin2
@GetMapping("isLogin2")
public SaResult isLogin2(ServerRequest request, ServerResponse response) {
SaResult res = SaTokenContextUtil.setContext(request, response, () -> {
System.out.println("是否登录:" + StpUtil.isLogin());
return SaResult.data(StpUtil.getTokenInfo());
});
return SaResult.data(res);
}
// API测试自动设置上下文lambda 表达式形式 --- http://localhost:8081/test/isLogin3
@GetMapping("isLogin3")
public Mono<SaResult> isLogin3() {
return SaReactorHolder.sync(() -> {
System.out.println("是否登录:" + StpUtil.isLogin());
userService.isLogin();
return SaResult.data(StpUtil.getTokenInfo());
});
}
// API测试自动设置上下文调用 userService Mono 方法 --- http://localhost:8081/test/isLogin4
@GetMapping("isLogin4")
public Mono<SaResult> isLogin4() {
return userService.findUserIdByNamePwd("ZhangSan", "123456")
.flatMap(userId -> SaReactorHolder.sync(() -> {
StpUtil.login(userId);
return SaResult.data(StpUtil.getTokenInfo());
}));
}
// API测试切换线程复杂嵌套调用 --- http://localhost:8081/test/isLogin5
@GetMapping("isLogin5")
public Mono<SaResult> isLogin5() {
System.out.println("线程id-----" + Thread.currentThread().getId());
// 要点在流里调用 Sa-Token API 之前必须用 SaReactorHolder.sync( () -> {} ) 进行包裹
return Mono.delay(Duration.ofSeconds(1))
.doOnNext(r -> System.out.println("线程id-----" + Thread.currentThread().getId()))
.map(r -> SaReactorHolder.sync(() -> userService.isLogin()))
.map(r -> userService.findUserIdByNamePwd("ZhangSan", "123456"))
.map(r -> SaReactorHolder.sync(() -> userService.isLogin()))
.flatMap(isLogin -> {
System.out.println("是否登录 " + isLogin);
return SaReactorHolder.sync(() -> {
System.out.println("是否登录 " + StpUtil.isLogin());
return SaResult.data(StpUtil.getTokenInfo());
});
});
}
// API测试使用上下文无关的API --- http://localhost:8081/test/isLogin6
@GetMapping("isLogin6")
public SaResult isLogin6(@CookieValue("satoken") String satoken) {
System.out.println("token 为:" + satoken);
System.out.println("登录人:" + StpUtil.getLoginIdByToken(satoken));
return SaResult.ok("登录人:" + StpUtil.getLoginIdByToken(satoken));
}
// 测试 浏览器访问 http://localhost:8081/test/test
@GetMapping("test")
public SaResult test() {
System.out.println("线程id------- " + Thread.currentThread().getId());
return SaResult.ok();
}
}

View File

@ -0,0 +1,24 @@
package com.pj.test;
import cn.dev33.satoken.stp.StpUtil;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Service;
import reactor.core.publisher.Mono;
/**
* 模拟 Service 方法
* @author click33
* @since 2025/4/6
*/
@Service
public class UserService {
public boolean isLogin() {
System.out.println("UserService 里调用 API 测试,是否登录:" + StpUtil.isLogin());
return StpUtil.isLogin();
}
public Mono<Long> findUserIdByNamePwd(String name, String pwd) {
// ...
return Mono.just(10001L);
}
}

View File

@ -0,0 +1,4 @@
# 端口
k:
server:
port: 8081

View File

@ -17,7 +17,7 @@
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<!-- 定义 Sa-Token 版本号 -->
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -17,7 +17,7 @@
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<!-- 定义 Sa-Token 版本号 -->
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -16,12 +16,14 @@ import java.util.List;
@Component
public class SaClientMockDao {
public List<SaClientModel> list = new ArrayList<>();
public List<SaClientModel> list;
/**
* 构造方法添加三个模拟应用
*/
public SaClientMockDao(){
public void init(){
list = new ArrayList<>();
// 模拟应用1
SaClientModel client1 = new SaClientModel()
.setClientId("1001") // client id
@ -77,6 +79,9 @@ public class SaClientMockDao {
* @return 应用对象
*/
public SaClientModel getClientModel(String clientId) {
if(list == null) {
init();
}
return list.stream()
.filter(e -> e.getClientId().equals(clientId))
.findFirst()

View File

@ -3,6 +3,7 @@ package com.pj.oauth2;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.oauth2.config.SaOAuth2ServerConfig;
import cn.dev33.satoken.oauth2.processor.SaOAuth2ServerProcessor;
import cn.dev33.satoken.oauth2.strategy.SaOAuth2Strategy;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.beans.factory.annotation.Autowired;
@ -32,12 +33,12 @@ public class SaOAuth2ServerController {
@Autowired
public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) {
// 未登录的视图
oauth2Server.notLoginView = ()->{
SaOAuth2Strategy.instance.notLoginView = ()->{
return new ModelAndView("login.html");
};
// 登录处理函数
oauth2Server.doLoginHandle = (name, pwd) -> {
SaOAuth2Strategy.instance.doLoginHandle = (name, pwd) -> {
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
return SaResult.ok().set("satoken", StpUtil.getTokenValue());
@ -46,7 +47,7 @@ public class SaOAuth2ServerController {
};
// 授权确认视图
oauth2Server.confirmView = (clientId, scopes)->{
SaOAuth2Strategy.instance.confirmView = (clientId, scopes)->{
Map<String, Object> map = new HashMap<>();
map.put("clientId", clientId);
map.put("scope", scopes);

View File

@ -0,0 +1,27 @@
//package com.pj.oauth2.custom_grant_type;
//
//import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
//import cn.dev33.satoken.oauth2.granttype.handler.PasswordGrantTypeHandler;
//import cn.dev33.satoken.oauth2.granttype.handler.model.PasswordAuthResult;
//import org.springframework.stereotype.Component;
//
///**
// * 自定义 Password Grant_Type 授权模式处理器认证过程
// *
// * @author click33
// * @since 2025/5/11
// */
//@Component
//public class CustomPasswordGrantTypeHandler extends PasswordGrantTypeHandler {
//
// @Override
// public PasswordAuthResult loginByUsernamePassword(String username, String password) {
// if("sa".equals(username) && "123456".equals(password)) {
// long userId = 10001;
// return new PasswordAuthResult(userId);
// } else {
// throw new SaOAuth2Exception("无效账号密码");
// }
// }
//
//}

View File

@ -1,4 +1,4 @@
//package com.pj.oauth2.custom;
//package com.pj.oauth2.custom_grant_type;
//
//import cn.dev33.satoken.SaManager;
//import cn.dev33.satoken.context.model.SaRequest;

View File

@ -1,4 +1,4 @@
//package com.pj.oauth2.custom;
//package com.pj.oauth2.custom_grant_type;
//
//import cn.dev33.satoken.SaManager;
//import cn.dev33.satoken.util.SaFoxUtil;

View File

@ -1,4 +1,4 @@
//package com.pj.oauth2.custom;
//package com.pj.oauth2.custom_scope;
//
//import cn.dev33.satoken.oauth2.data.model.oidc.IdTokenModel;
//import cn.dev33.satoken.oauth2.scope.handler.OidcScopeHandler;
@ -19,10 +19,11 @@
// System.out.println("----- 为 idToken 追加扩展字段 ----- ");
//
// idToken.extraData.put("uid", userId); // 用户id
// idToken.extraData.put("nickname", "lin_xiao_lin"); // 昵称
// idToken.extraData.put("nickname", "linXiaoLin"); // 昵称
// idToken.extraData.put("picture", "https://sa-token.cc/logo.png"); // 头像
// idToken.extraData.put("email", "456456@xx.com"); // 邮箱
// idToken.extraData.put("phone_number", "13144556677"); // 手机号
//
// // 更多字段 ...
// // 可参考https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
//

View File

@ -1,4 +1,4 @@
//package com.pj.oauth2.custom;
//package com.pj.oauth2.custom_scope;
//
//import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
//import cn.dev33.satoken.oauth2.data.model.ClientTokenModel;
@ -9,17 +9,20 @@
//import java.util.Map;
//
///**
// * 自定义 userinfo scope 处理器
// * @author click33
// * @since 2024/8/20
// */
//@Component
//public class UserinfoScopeHandler implements SaOAuth2ScopeHandlerInterface {
//
// // 指示当前处理器所要处理的 scope
// @Override
// public String getHandlerScope() {
// return "userinfo";
// }
//
// // 当构建的 AccessToken 具有此权限时所需要执行的方法
// @Override
// public void workAccessToken(AccessTokenModel at) {
// System.out.println("--------- userinfo 权限,加工 AccessTokenModel --------- ");
@ -34,8 +37,16 @@
// at.extraData.put("userinfo", map);
// }
//
// // 当构建的 ClientToken 具有此权限时所需要执行的方法
// @Override
// public void workClientToken(ClientTokenModel ct) {
// }
//
// // 当使用 RefreshToken 刷新 AccessToken 是否重新执行 workAccessToken 构建方法
// // 在一些实时性较高的数据中需要指定为 true
// @Override
// public boolean refreshAccessTokenIsWork() {
// return true;
// }
//
//}

View File

@ -8,10 +8,12 @@ import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.data.generate.SaOAuth2DataGenerate;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.data.model.CodeModel;
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
import cn.dev33.satoken.oauth2.data.model.request.RequestAuthModel;
import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode;
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
import cn.dev33.satoken.oauth2.processor.SaOAuth2ServerProcessor;
import cn.dev33.satoken.oauth2.strategy.SaOAuth2Strategy;
import cn.dev33.satoken.oauth2.template.SaOAuth2Template;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.PostMapping;
@ -54,20 +56,26 @@ public class SaOAuth2ServerH5Controller {
// 3构建请求 Model
RequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, loginId);
// 4校验重定向域名是否合法
// 4开发者自定义的授权前置检查
SaOAuth2Strategy.instance.userAuthorizeClientCheck.run(ra.loginId, ra.clientId);
// 5校验重定向域名是否合法
oauth2Template.checkRedirectUri(ra.clientId, ra.redirectUri);
// 5校验此次申请的Scope该Client是否已经签约
// 6校验此次申请的Scope该Client是否已经签约
oauth2Template.checkContractScope(ra.clientId, ra.scopes);
// 6判断如果此次申请的Scope该用户尚未授权则转到授权页面
// 7判断如果此次申请的Scope该用户尚未授权则转到授权页面
boolean isNeedCarefulConfirm = oauth2Template.isNeedCarefulConfirm(ra.loginId, ra.clientId, ra.scopes);
if(isNeedCarefulConfirm) {
// code=411需要用户手动确认授权
return SaResult.get(411, "need confirm", null);
SaClientModel cm = oauth2Template.checkClientModel(ra.clientId);
if( ! cm.getIsAutoConfirm()) {
// code=411需要用户手动确认授权
return SaResult.get(411, "need confirm", null);
}
}
// 7判断授权类型重定向到不同地址
// 8判断授权类型重定向到不同地址
// 如果是 授权码式开始重定向授权下放code
if(SaOAuth2Consts.ResponseType.code.equals(ra.responseType)) {
CodeModel codeModel = dataGenerate.generateCode(ra);

View File

@ -0,0 +1,108 @@
package com.pj.test;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.template.SaOAuth2Util;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* 测试 OAuth2 相关 token 增删查
*
* @author click33
* @since 2024/8/25
*/
@RestController
@RequestMapping("/test")
public class Test2Controller {
// 测试查询全部 Access-Token --- http://localhost:8000/test/getAccessTokenValueList?clientId=1001&loginId=10001
@RequestMapping("/getAccessTokenValueList")
public SaResult getAccessTokenValueList(String clientId, long loginId) {
List<String> accessTokenValueList = SaOAuth2Util.getAccessTokenValueList(clientId, loginId);
return SaResult.data(accessTokenValueList);
}
// 测试查询全部 Access-Token, 带过期时间 --- http://localhost:8000/test/getAccessTokenIndexMap?clientId=1001&loginId=10001
@RequestMapping("/getAccessTokenIndexMap")
public SaResult getAccessTokenIndexMap(String clientId, long loginId) {
Map<String, Long> accessTokenIndexMap = SaOAuth2Manager.getDao().getAccessTokenIndexMap_FromAdjustAfter(clientId, loginId);
return SaResult.data(accessTokenIndexMap);
}
// 测试回收指定 Access-Token --- http://localhost:8000/test/revokeAccessToken?access_token=xxxxxxxxxx
@RequestMapping("/revokeAccessToken")
public SaResult revokeAccessToken(String access_token) {
SaOAuth2Util.revokeAccessToken(access_token);
return SaResult.ok();
}
// 测试回收全部 Access-Token --- http://localhost:8000/test/revokeAccessTokenByIndex?clientId=1001&loginId=10001
@RequestMapping("/revokeAccessTokenByIndex")
public SaResult revokeAccessTokenByIndex(String clientId, long loginId) {
SaOAuth2Util.revokeAccessTokenByIndex(clientId, loginId);
return SaResult.ok();
}
// 测试查询全部 Refresh-Token --- http://localhost:8000/test/getRefreshTokenValueList?clientId=1001&loginId=10001
@RequestMapping("/getRefreshTokenValueList")
public SaResult getRefreshTokenValueList(String clientId, long loginId) {
List<String> refreshTokenValueList = SaOAuth2Util.getRefreshTokenValueList(clientId, loginId);
return SaResult.data(refreshTokenValueList);
}
// 测试查询全部 Refresh-Token, 带过期时间 --- http://localhost:8000/test/getRefreshTokenIndexMap?clientId=1001&loginId=10001
@RequestMapping("/getRefreshTokenIndexMap")
public SaResult getRefreshTokenIndexMap(String clientId, long loginId) {
Map<String, Long> refreshTokenIndexMap = SaOAuth2Manager.getDao().getRefreshTokenIndexMap_FromAdjustAfter(clientId, loginId);
return SaResult.data(refreshTokenIndexMap);
}
// 测试回收指定 Refresh-Token --- http://localhost:8000/test/revokeRefreshToken?refresh_token=xxxxxxxxxx
@RequestMapping("/revokeRefreshToken")
public SaResult revokeRefreshToken(String refresh_token) {
SaOAuth2Util.revokeRefreshToken(refresh_token);
return SaResult.ok();
}
// 测试回收全部 Refresh-Token --- http://localhost:8000/test/revokeRefreshTokenByIndex?clientId=1001&loginId=10001
@RequestMapping("/revokeRefreshTokenByIndex")
public SaResult revokeRefreshTokenByIndex(String clientId, long loginId) {
SaOAuth2Util.revokeRefreshTokenByIndex(clientId, loginId);
return SaResult.ok();
}
// 测试查询全部 Client-Token --- http://localhost:8000/test/getClientTokenValueList?clientId=1001
@RequestMapping("/getClientTokenValueList")
public SaResult getClientTokenValueList(String clientId) {
List<String> clientTokenValueList = SaOAuth2Util.getClientTokenValueList(clientId);
return SaResult.data(clientTokenValueList);
}
// 测试查询全部 Client-Token, 带过期时间 --- http://localhost:8000/test/getClientTokenIndexMap?clientId=1001&loginId=10001
@RequestMapping("/getClientTokenIndexMap")
public SaResult getClientTokenIndexMap(String clientId, long loginId) {
Map<String, Long> rlientTokenIndexMap = SaOAuth2Manager.getDao().getClientTokenIndexMap_FromAdjustAfter(clientId, loginId);
return SaResult.data(rlientTokenIndexMap);
}
// 测试回收指定 Client-Token --- http://localhost:8000/test/revokeClientToken?client_token=xxxxxxxxxxx
@RequestMapping("/revokeClientToken")
public SaResult revokeClientToken(String client_token) {
SaOAuth2Util.revokeClientToken(client_token);
return SaResult.ok();
}
// 测试回收全部 Client-Token --- http://localhost:8000/test/revokeClientTokenByIndex?clientId=1001
@RequestMapping("/revokeClientTokenByIndex")
public SaResult revokeClientTokenByIndex(String clientId) {
SaOAuth2Util.revokeClientTokenByIndex(clientId);
return SaResult.ok();
}
}

View File

@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -17,7 +17,7 @@
</parent>
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -10,13 +10,13 @@
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>3.0.1</version>
<version>3.2.1</version>
<relativePath/>
</parent>
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

View File

@ -10,7 +10,7 @@
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>3.0.4</version>
<version>3.2.1</version>
<relativePath/>
</parent>
@ -19,7 +19,7 @@
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.traget>17</maven.compiler.traget>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
@ -51,6 +51,13 @@
<version>${sa-token.version}</version>
</dependency>
<!-- sa-token json 序列化器组件snack3 实现 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-snack3</artifactId>
<version>${sa-token.version}</version>
</dependency>
<!-- hutool工具类用来生成雪花算法唯一id -->
<!-- <dependency>
<groupId>cn.hutool</groupId>

View File

@ -19,7 +19,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
<java.run.main.class>com.pj.SaTokenApplication</java.run.main.class>
<java.version>1.8</java.version>
</properties>

View File

@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

View File

@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.42.0</sa-token.version>
<sa-token.version>1.44.0</sa-token.version>
</properties>
<dependencies>

Some files were not shown because too many files have changed in this diff Show More