1
0
mirror of synced 2026-05-22 22:53:16 +00:00

Compare commits

...

100 Commits

Author SHA1 Message Date
click33 c0587d5e92 Merge branch 'dev' of https://github.com/dromara/Sa-Token into dev 2023-09-22 03:51:21 +08:00
click33 33ece1a2b0 v1.36.0 update. 2023-09-22 03:50:55 +08:00
click33 1fcda76ce4 v1.36.0 update 2023-09-22 03:42:41 +08:00
click33 e32979a7a6 v1.36.0 update 2023-09-22 02:54:35 +08:00
click33 6da234d285 添加路由匹配单元测试 2023-09-22 02:14:18 +08:00
刘潇 5ec6c42671 !282 v1.35.1
Merge pull request !282 from 刘潇/v1.35.1
2023-09-21 17:08:52 +00:00
click33 686cef5a8e 添加公司案例 2023-09-20 19:32:01 +08:00
click33 cf58444bf0 增加友联:spring-file-storage 2023-09-19 16:53:00 +08:00
click33 2cfb8df28a Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-09-12 19:26:38 +08:00
click33 83268da0cb 优化文档 2023-09-12 19:26:28 +08:00
刘潇 ac2d65042c update sa-token-doc/start/new-version.md.
Signed-off-by: 刘潇 <2393584716@qq.com>
2023-09-07 10:12:38 +00:00
刘潇 6dfa750821 !278 Solon 框架升为:2.5.3
Merge pull request !278 from 西东/dev
2023-09-04 09:30:31 +00:00
noear e76169864d Solon 框架升为:2.5.3 2023-09-04 13:29:08 +08:00
click33 fcf3cc43f4 ... 2023-09-03 12:52:40 +08:00
click33 56cb20aff6 增加友联 2023-09-03 12:52:13 +08:00
click33 c09f5ae20e ... 2023-09-03 12:51:58 +08:00
Uncarbon e74a589b88 !277 docs: 「微服务」节文档完善
* docs: 「微服务」节文档格式完善
* docs: boot3版的依赖名未同步至「微服务」节中;「服务」👉「服务间」
2023-09-02 07:39:53 +00:00
click33 31b410eadd Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-09-02 15:34:24 +08:00
click33 5c2d6076c9 beautify qr 2023-09-02 15:33:51 +08:00
孔明 d1d5716ddc update README.md.
Signed-off-by: 孔明 <2393584716@qq.com>
2023-09-01 06:10:54 +00:00
孔明 8506f234aa !276 docs: 将「Q:开启了全局懒加载后,能启动项目,但是访问接口报未能获取有效的上下文处理器」问题链接加入前置的「Q:报错:未能获取有效的上下文处理器。」中
Merge pull request !276 from Uncarbon/dev
2023-09-01 03:23:32 +00:00
Uncarbon 5120cfa1bb docs: 将「Q:开启了全局懒加载后,能启动项目,但是访问接口报未能获取有效的上下文处理器」问题链接加入前置的「Q:报错:未能获取有效的上下文处理器。」中 2023-09-01 11:19:01 +08:00
click33 4c35f9e936 常见问答增加新问题 2023-08-30 11:26:27 +08:00
click33 d59b27cc66 去除不必要的注释 2023-08-24 13:44:31 +08:00
click33 13ff5c8306 Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-08-24 13:01:16 +08:00
click33 195697c2b3 更新赞助者名单 2023-08-24 13:00:50 +08:00
click33 759dfc79cc 缩小请求权限范围 2023-08-24 12:58:45 +08:00
孔明 35b37b0aea !273 【轻量级PR】:加密工具类增加实现
Merge pull request !273 from 995zwj若初/dev
2023-08-21 10:02:19 +00:00
若初 4c65c0be08 移除不必要final 2023-08-21 17:15:38 +08:00
若初 180fe0791b pom修改 2023-08-21 12:41:04 +08:00
若初 b42deb823b 1、加密工具类增加sha384以及sha512,抽取sha公共方法,增加加密异常码
2、优化代码规范提示
2023-08-21 12:34:10 +08:00
click33 60cdb12c69 更新赞助者名单 2023-08-18 15:38:50 +08:00
click33 871422044b Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-08-18 15:23:34 +08:00
click33 7db7880f09 更新 dromara 成员项目 2023-08-18 15:23:25 +08:00
孔明 aadad9bfa3 update README.md.
Signed-off-by: 孔明 <2393584716@qq.com>
2023-08-18 07:14:49 +00:00
click33 480c74d131 优化文档 2023-08-12 15:35:12 +08:00
click33 b867787b0e 添加新博客链接 2023-08-10 15:12:05 +08:00
click33 d901a45552 sa-token 小助手增加提示信息 2023-08-10 13:17:07 +08:00
click33 6f8a3a4249 sa-token 小助手增加提示信息 2023-08-09 13:33:01 +08:00
click33 f5586a94ea 修复 sa-token 小助手提示信息的不正确描述 2023-08-09 11:50:11 +08:00
click33 1f84ea6939 上线 sa-token 小助手 2023-08-09 11:29:43 +08:00
click33 0d69bde2ba 添加案例 2023-08-08 23:37:03 +08:00
click33 2ef8a82614 update doc 2023-08-07 10:47:34 +08:00
孔明 05e8e8d130 update README.md.
Signed-off-by: 孔明 <2393584716@qq.com>
2023-08-04 11:45:39 +00:00
click33 e30f4df048 优化 StpLogic#getLoginId 返回值逻辑 2023-08-04 16:51:21 +08:00
click33 45fcfc5e8e Merge pull request #497 from shenchunping/dev
fix: 修复getLoginId,默认值空报错
2023-08-04 16:36:48 +08:00
click33 8c3477b48f Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-08-04 16:02:09 +08:00
click33 45a77612ef 升级模糊匹配算法 2023-08-04 16:01:58 +08:00
孔明 296704c7c5 !267 update README.md.
Merge pull request !267 from AppleOfGray/N/A
2023-08-04 07:22:40 +00:00
AppleOfGray 42d1872553 update README.md.
更新链接地址
2023-08-04 06:04:39 +00:00
click33 f162834ded 增加新的报错排查 2023-08-04 11:29:45 +08:00
shenchunping 7278467411 fix: 修复getLoginId,默认值空报错 2023-08-03 08:27:15 +08:00
click33 5e9f58935c 去除友盟数据统计代码 2023-08-01 13:31:12 +08:00
click33 dd8c55ed3c 新增友情链接 2023-08-01 13:25:04 +08:00
click33 270ec74f84 修复外链地址 2023-07-31 11:14:59 +08:00
click33 ffc487f7cb Merge branch 'dev' of https://github.com/dromara/sa-token into dev 2023-07-31 11:05:53 +08:00
click33 083164617c 文档增加ad信息 2023-07-31 11:01:25 +08:00
click33 11664157a4 Merge pull request #489 from weloe/dev-fixdocs
docs: 修复javadoc
2023-07-28 10:45:03 +08:00
click33 b896173d5f Merge pull request #485 from ljngtan/dev
Add sa-token-reactor-spring-boot3-starter to the bom
2023-07-28 10:41:18 +08:00
click33 17fa35e251 优化 sign 签名验证的逻辑 2023-07-28 10:07:12 +08:00
click33 6566f60410 优化文档 2023-07-28 10:06:49 +08:00
click33 4a57a8ebdc 优化文档 2023-07-28 07:11:33 +08:00
click33 b3b89ebf53 去除 nonce 非空校验 2023-07-28 01:19:01 +08:00
孔明 62f92e9097 !261 修复 API接口签名校验参数接口NPE问题,增加必须参数的非空校验处理。
Merge pull request !261 from KonBAI/dev
2023-07-27 17:17:24 +00:00
孔明 559fba69b8 !264 fix(SaFoxUtil): 修复权限正则匹配模式
Merge pull request !264 from CZHao/dev
2023-07-27 17:08:22 +00:00
click33 a19fadbd54 优化文档 2023-07-28 00:35:02 +08:00
孔明 18d360799e !265 sa-token-solon-plugin 增加对 solon 网关的支持
Merge pull request !265 from 西东/dev
2023-07-27 15:43:50 +00:00
click33 d3911deec7 优化文档 2023-07-27 20:16:28 +08:00
click33 1a1d90787a Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-07-27 19:43:53 +08:00
click33 fa3297d5f9 修复群链接打不开的问题 2023-07-27 19:38:43 +08:00
click33 b0e4864782 优化文档 star 2023-07-27 06:36:55 +08:00
click33 3193727486 优化文档. 2023-07-27 01:11:43 +08:00
weloe d2266d6967 docs: 修复javadoc 2023-07-26 20:30:06 +08:00
noear 172351ad04 sa-token-solon-plugin 增加对 solon 网关的支持 2023-07-26 10:15:36 +08:00
CZHao a1a67ca606 fix(SaFoxUtil): 修复权限正则匹配模式
旧代码存在:
user.* 会匹配 usermgt.list
新代码修复:
user.* 只会匹配 user.add user.update 等,匹配模式必须包含user.前缀
且使用replace性能比replaceAll正则替换要高
2023-07-25 10:04:18 +08:00
孔明 26c312f8d6 update sa-token-doc/more/sa-token-donate.md.
Signed-off-by: 孔明 <2393584716@qq.com>
2023-07-24 11:43:33 +00:00
click33 9b009d0d79 Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-07-24 09:13:52 +08:00
click33 f023326556 添加公众号 2023-07-24 09:13:44 +08:00
click33 3b9b2f8791 优化文档 2023-07-24 07:44:56 +08:00
click33 deb778ed41 优化文档 2023-07-21 20:55:48 +08:00
ljngtan 3d49ce7092 Add sa-token-reactor-spring-boot3-starter to the bom 2023-07-21 14:15:53 +08:00
孔明 705101256a !263 Solon 框架升为:2.4.0
Merge pull request !263 from 西东/dev
2023-07-20 12:21:00 +00:00
noear 289d9c966c Solon 框架升为:2.4.0 2023-07-20 20:12:41 +08:00
click33 186d8c6c8c 添加忽略目录 2023-07-20 02:01:44 +08:00
click33 0f875ae9e5 优化文档 2023-07-19 23:55:49 +08:00
click33 a799b4cc49 同步案例 2023-07-16 17:16:35 +08:00
click33 d006cf806d Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-07-16 16:55:50 +08:00
click33 1add5403e8 添加公司案例 2023-07-16 16:55:38 +08:00
孔明 09d3acf775 !262 修改checkLoginArgs方法内的注释
Merge pull request !262 from tan90/dev
2023-07-12 15:40:50 +00:00
陈浩杰 d5c8108996 调整注释文本 2023-07-12 09:38:21 +08:00
konbai f832c63a8c 修复 API接口签名校验参数接口NPE问题,增加必须参数的非空校验处理。 2023-07-11 23:08:47 +08:00
孔明 072a76132a !260 sa-token-redisson-jackson2 添加 readme,并添加 sa-token-demo-solon-redisson
Merge pull request !260 from 西东/dev
2023-07-04 02:40:05 +00:00
noear 1d1aed3719 sa-token-redisson-jackson2 添加 readme,并添加 sa-token-demo-solon-redisson 2023-07-04 10:20:48 +08:00
孔明 b16d033734 !258 添加通用模块 sa-token-redisson-jackson2(spring, solon, jfinal 等都可用)
Merge pull request !258 from 西东/dev
2023-07-04 01:26:18 +00:00
孔明 78238641a3 !257 删除不必要检测代码
Merge pull request !257 from AppleOfGray/dev
2023-07-04 01:25:50 +00:00
noear b49c5f9a5f 调整代码格式 2023-06-28 07:16:27 +08:00
noear e01b98e55a 调整代码格式 2023-06-28 07:15:26 +08:00
noear 4555c48df9 添加通用模块 sa-token-redisson-jackson2(spring, solon, jfinal 等都可用) 2023-06-28 07:09:19 +08:00
hjc d8dc6f51cf 添加新经验 2023-06-27 21:07:21 +08:00
hjc 1f5798176d 既然加入了依赖肯定是需要读取配置的, 这个属性检查就去掉吧 2023-06-27 20:45:12 +08:00
105 changed files with 3421 additions and 467 deletions
+2
View File
@@ -13,4 +13,6 @@ unpackage/
.idea/
sa-token-three-plugin/
.flattened-pom.xml
+12 -7
View File
@@ -1,7 +1,7 @@
<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.35.0.RC</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.36.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>
@@ -18,9 +18,9 @@
## 前言:
- [在线文档:https://sa-token.cc](https://sa-token.cc)
- 注:学习测试请拉取 master 分支,dev 为正在开发分支,有很多特性并不稳定。
- 注:学习测试请拉取 master 分支,dev 开发分支,有很多特性并不稳定(在项目根目录执行 `git checkout master`
- 开源不易,点个 star 鼓励一下吧!
- 开源不易,点个 star 鼓励一下吧!
## Sa-Token 介绍
@@ -150,9 +150,9 @@ Sa-OAuth2 模块分为四种授权模式,解决不同场景下的授权需求
- [[ Snowy ]](https://gitee.com/xiaonuobase/snowy):国内首个国密前后分离快速开发平台,采用 Vue3 + AntDesignVue3 + Vite + SpringBoot + Mp + HuTool + SaToken。
- [[ RuoYi-Vue-Plus ]](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus):重写RuoYi-Vue所有功能 集成 Sa-Token+Mybatis-Plus+Jackson+Xxl-Job+knife4j+Hutool+OSS 定期同步
- [[ RuoYi-Vue-Plus ]](https://gitee.com/dromara/RuoYi-Vue-Plus):重写RuoYi-Vue所有功能 集成 Sa-Token+Mybatis-Plus+Jackson+Xxl-Job+knife4j+Hutool+OSS 定期同步
- [[ RuoYi-Cloud-Plus ]](https://gitee.com/JavaLionLi/RuoYi-Cloud-Plus):重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba Dubbo3.0 Sa-Token Mybatis-Plus MQ OSS ES Xxl-Job Docker 全方位升级 定期同步
- [[ RuoYi-Cloud-Plus ]](https://gitee.com/dromara/RuoYi-Cloud-Plus):重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba Dubbo3.0 Sa-Token Mybatis-Plus MQ OSS ES Xxl-Job Docker 全方位升级 定期同步
- [[ EasyAdmin ]](https://gitee.com/lakernote/easy-admin):一个基于SpringBoot2 + Sa-Token + Mybatis-Plus + Snakerflow + Layui 的后台管理系统,灵活多变可前后端分离,也可单体,内置代码生成器、权限管理、工作流引擎等
@@ -174,17 +174,22 @@ Sa-OAuth2 模块分为四种授权模式,解决不同场景下的授权需求
- [[ hippo4j ]](https://gitee.com/agentart/hippo4j):强大的动态线程池框架,附带监控报警功能。
- [[ hertzbeat ]](https://gitee.com/dromara/hertzbeat):易用友好的开源实时监控告警系统,无需Agent,高性能集群,强大自定义监控能力。
- [[ Solon ]](https://gitee.com/noear/solon):一个更现代感的应用开发框架:更快、更小、更自由。
## 知识星球
<img src="https://oss.dev33.cn/sa-token/dromara-xingqiu--sa-token.jpg" width="300px" />
## 交流群
QQ交流群:707350988 [点击加入](https://jq.qq.com/?_wv=1027&k=tqbzHT2D)
QQ交流群:837325627 [点击加入](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=98NOhX0Q3a2hcv3eURcnYMBuZUZrlHUH&authKey=td3pmX3BnYNr%2FCRkEDwE5FgGARk29D9HAMwL0bAfK7tqN8XN93jccnEanyZl18mM&noverify=0&group_code=837325627)
微信交流群:
![微信群](https://dev33-test.oss-cn-beijing.aliyuncs.com/sa-token/i-wx-qr.png ':size=230')
<img src="https://oss.dev33.cn/sa-token/qr/wx-qr-m-400k.png" width="230px" title="微信群" />
<!-- ![微信群](https://dev33-test.oss-cn-beijing.aliyuncs.com/sa-token/i-wx-qr.png ':size=230') -->
(扫码添加微信,备注:sa-token,邀您加入群聊)
+1 -1
View File
@@ -37,7 +37,7 @@
<!-- 一些属性 -->
<properties>
<revision>1.35.0.RC</revision>
<revision>1.36.0</revision>
<jdk.version>1.8</jdk.version>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>
+12 -2
View File
@@ -13,7 +13,7 @@
<url>https://github.com/dromara/sa-token</url>
<properties>
<revision>1.35.0.RC</revision>
<revision>1.36.0</revision>
</properties>
<dependencyManagement>
@@ -46,6 +46,11 @@
<artifactId>sa-token-reactor-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-reactor-spring-boot3-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-servlet</artifactId>
@@ -124,6 +129,11 @@
<artifactId>sa-token-redisson-jackson</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisson-jackson2</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisx</artifactId>
@@ -249,4 +259,4 @@
</pluginManagement>
</build>
</project>
</project>
-1
View File
@@ -3,7 +3,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-parent</artifactId>
@@ -154,6 +154,12 @@ public interface SaErrorCode {
/** sha256 加密异常 */
int CODE_12113 = 12113;
/** sha384 加密异常 */
int CODE_121131 = 121131;
/** sha512 加密异常 */
int CODE_121132 = 121132;
/** AES 加密异常 */
int CODE_12114 = 12114;
@@ -91,20 +91,8 @@ public class SaSecureUtil {
public static String sha1(String str) {
try {
str = (str == null ? "" : str);
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] b = str.getBytes();
md.update(b);
byte[] b2 = md.digest();
int len = b2.length;
String strA = "0123456789abcdef";
char[] ch = strA.toCharArray();
char[] chs = new char[len * 2];
for (int i = 0, k = 0; i < len; i++) {
byte b3 = b2[i];
chs[k++] = ch[b3 >>> 4 & 0xf];
chs[k++] = ch[b3 & 0xf];
}
return new String(chs);
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
return getShaHexString(str, messageDigest);
} catch (Exception e) {
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12112);
}
@@ -120,25 +108,67 @@ public class SaSecureUtil {
try {
str = (str == null ? "" : str);
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(str.getBytes(StandardCharsets.UTF_8));
byte[] bytes = messageDigest.digest();
StringBuilder builder = new StringBuilder();
String temp;
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
builder.append("0");
}
builder.append(temp);
}
return builder.toString();
return getShaHexString(str, messageDigest);
} catch (Exception e) {
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12113);
}
}
/**
* sha384加密
*
* @param str 指定字符串
* @return 加密后的字符串
*/
public static String sha384(String str) {
try {
str = (str == null ? "" : str);
MessageDigest messageDigest = MessageDigest.getInstance("SHA-384");
return getShaHexString(str, messageDigest);
} catch (Exception e) {
throw new SaTokenException(e).setCode(SaErrorCode.CODE_121131);
}
}
/**
* sha512加密
*
* @param str 指定字符串
* @return 加密后的字符串
*/
public static String sha512(String str) {
try {
str = (str == null ? "" : str);
MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
return getShaHexString(str, messageDigest);
} catch (Exception e) {
throw new SaTokenException(e).setCode(SaErrorCode.CODE_121132);
}
}
/**
* sha (Secure Hash Algorithm)加密 公共方法
*
* @param str 指定字符串
* @param messageDigest 消息摘要
* @return 加密后的字符串
*/
private static String getShaHexString(String str, MessageDigest messageDigest) {
messageDigest.update(str.getBytes(StandardCharsets.UTF_8));
byte[] bytes = messageDigest.digest();
StringBuilder builder = new StringBuilder();
String temp;
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF); // 获取无符号整数十六进制字符串
if (temp.length() == 1) {
builder.append("0"); // 确保每个字节都用两个字符表示
}
builder.append(temp);
}
return builder.toString();
}
/**
* md5加盐加密: md5(md5(str) + md5(salt))
* @param str 字符串
@@ -149,6 +179,15 @@ public class SaSecureUtil {
return md5(md5(str) + md5(salt));
}
/**
* sha256加盐加密: sha256(sha256(str) + sha256(salt))
* @param str 字符串
* @param salt 盐
* @return 加密后的字符串
*/
public static String sha256BySalt(String str, String salt) {
return sha256(sha256(str) + sha256(salt));
}
// ----------------------- 对称加密 AES -----------------------
@@ -294,9 +294,9 @@ public class SaSignTemplate {
String nonceValue = paramMap.get(nonce);
String signValue = paramMap.get(sign);
// 三个参数必须全部非空
// 参数非空校验
SaSignException.throwByNull(timestampValue, "缺少 timestamp 字段");
SaSignException.throwByNull(nonceValue, "缺少 nonce 字段");
// SaSignException.throwByNull(nonceValue, "缺少 nonce 字段"); // 配置isCheckNonce=false时,可以不传 nonce
SaSignException.throwByNull(signValue, "缺少 sign 字段");
// 三个值的校验必须全部通过
@@ -315,6 +315,11 @@ public class SaSignTemplate {
String nonceValue = paramMap.get(nonce);
String signValue = paramMap.get(sign);
// 参数非空校验
SaSignException.throwByNull(timestampValue, "缺少 timestamp 字段");
// SaSignException.throwByNull(nonceValue, "缺少 nonce 字段"); // 配置isCheckNonce=false时,可以不传 nonce
SaSignException.throwByNull(signValue, "缺少 sign 字段");
// 依次校验三个参数
checkTimestamp(Long.parseLong(timestampValue));
if(getSignConfigOrGlobal().getIsCheckNonce()) {
@@ -569,7 +569,7 @@ public class StpLogic {
throw new SaTokenException("loginId 不能为以下值:" + NotLoginException.ABNORMAL_LIST);
}
// 3、账号 id 不能是简单类型
// 3、账号 id 不能是复杂类型
if( ! SaFoxUtil.isBasicType(id.getClass())) {
SaManager.log.warn("loginId 应该为简单类型,例如:String | int | long,不推荐使用复杂类型:" + id.getClass());
}
@@ -994,9 +994,11 @@ public class StpLogic {
if(loginId == null) {
return defaultValue;
}
// 3、不为 null,则开始尝试类型转换
return (T)SaFoxUtil.getValueByType(loginId, defaultValue.getClass());
// 3、loginId 不为 null,则开始尝试类型转换
if (defaultValue == null) {
return null;
}
return (T) SaFoxUtil.getValueByType(loginId, defaultValue.getClass());
}
/**
@@ -251,8 +251,39 @@ public class SaFoxUtil {
if( ! patt.contains("*")) {
return patt.equals(str);
}
// 正则匹配
return Pattern.matches(patt.replaceAll("\\*", ".*"), str);
// 深入匹配
return vagueMatchMethod(patt, str);
}
/**
* 字符串模糊匹配
*
* @param pattern /
* @param str /
* @return /
*/
private static boolean vagueMatchMethod( String pattern, String str) {
int m = str.length();
int n = pattern.length();
boolean[][] dp = new boolean[m + 1][n + 1];
dp[0][0] = true;
for (int i = 1; i <= n; ++i) {
if (pattern.charAt(i - 1) == '*') {
dp[0][i] = true;
} else {
break;
}
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (pattern.charAt(j - 1) == '*') {
dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
} else if (str.charAt(i - 1) == pattern.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
}
}
}
return dp[m][n];
}
/**
@@ -36,7 +36,7 @@ public class SaTokenConsts {
/**
* Sa-Token 当前版本号
*/
public static final String VERSION_NO = "v1.35.0.RC";
public static final String VERSION_NO = "v1.36.0";
/**
* Sa-Token 开源地址 Gitee
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -73,7 +73,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-bom</artifactId>
<version>1.35.0</version>
<version>1.36.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
+1 -1
View File
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
<java.run.main.class>com.pj.SaTokenCrossCookieApplication</java.run.main.class>
</properties>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
<java.run.main.class>com.pj.SaTokenCrossHeaderApplication</java.run.main.class>
</properties>
@@ -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.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
<dubbo.version>2.7.21</dubbo.version>
<nacos.version>1.4.2</nacos.version>
</properties>
@@ -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.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
<dubbo.version>2.7.21</dubbo.version>
<nacos.version>1.4.2</nacos.version>
</properties>
@@ -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.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
<dubbo.version>3.2.2</dubbo.version>
<nacos.version>2.2.2</nacos.version>
</properties>
@@ -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.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
<dubbo.version>3.2.2</dubbo.version>
<nacos.version>2.2.2</nacos.version>
</properties>
+1 -1
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.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
+1 -1
View File
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -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.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -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.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
</parent>
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -0,0 +1,84 @@
<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>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-demo-solon-redisson</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- Solon -->
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.4.0</version>
<relativePath/>
</parent>
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<!-- Solon 依赖 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-web</artifactId>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon.logging.simple</artifactId>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>redisson-solon-plugin</artifactId>
</dependency>
<!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-solon-plugin</artifactId>
<version>${sa-token.version}</version>
</dependency>
<!-- sa-token整合redis (使用jdk默认序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisson-jackson2</artifactId>
<version>${sa-token.version}</version>
</dependency>
<!-- hutool工具类,用来生成雪花算法唯一id -->
<!-- <dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.4</version>
</dependency> -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<compilerArgument>-parameters</compilerArgument>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,20 @@
package com.pj;
import cn.dev33.satoken.SaManager;
import org.noear.solon.Solon;
import org.noear.solon.annotation.SolonMain;
/**
* sa-token整合 solon 示例
* @author noear
*
*/
@SolonMain
public class SaTokenDemoApp {
public static void main(String[] args) {
Solon.start(SaTokenDemoApp.class, args);
System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig());
}
}
@@ -0,0 +1,51 @@
package com.pj.satoken;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.log.SaLog;
import cn.dev33.satoken.log.SaLogForConsole;
import cn.dev33.satoken.util.StrFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 将 Sa-Token log 信息转接到 slf4j 接口
*
* @author noear 2022/11/14 created
*/
//@Component
public class SaLogForSlf4j extends SaLogForConsole implements SaLog {
static final Logger log = LoggerFactory.getLogger(SaLogForSlf4j.class);
/**
* 打印日志到控制台
*
* @param level 日志等级
* @param str 字符串
* @param args 参数列表
*/
public void println(int level, String str, Object... args) {
SaTokenConfig config = SaManager.getConfig();
if (config.getIsLog() && level >= config.getLogLevelInt()) {
switch (level) {
case trace:
log.trace(LOG_PREFIX + StrFormatter.format(str, args));
break;
case debug:
log.debug(LOG_PREFIX + StrFormatter.format(str, args));
break;
case info:
log.info(LOG_PREFIX + StrFormatter.format(str, args));
break;
case warn:
log.warn(LOG_PREFIX + StrFormatter.format(str, args));
break;
case error:
case fatal:
log.error(LOG_PREFIX + StrFormatter.format(str, args));
break;
}
}
}
}
@@ -0,0 +1,51 @@
package com.pj.satoken;
import org.noear.solon.core.util.LogUtil;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.log.SaLog;
import cn.dev33.satoken.log.SaLogForConsole;
import cn.dev33.satoken.util.StrFormatter;
/**
* 将 Sa-Token log 信息转接到 Solon
*
* @author click33
* @since 2022-11-2
*/
//@Component
public class SaLogForSolon extends SaLogForConsole implements SaLog {
/**
* 打印日志到控制台
*
* @param level 日志等级
* @param str 字符串
* @param args 参数列表
*/
public void println(int level, String str, Object... args) {
SaTokenConfig config = SaManager.getConfig();
if (config.getIsLog() && level >= config.getLogLevelInt()) {
switch (level) {
case trace:
LogUtil.global().trace(LOG_PREFIX + StrFormatter.format(str, args));
break;
case debug:
LogUtil.global().debug(LOG_PREFIX + StrFormatter.format(str, args));
break;
case info:
LogUtil.global().info(LOG_PREFIX + StrFormatter.format(str, args));
break;
case warn:
LogUtil.global().warn(LOG_PREFIX + StrFormatter.format(str, args));
break;
case error:
case fatal:
LogUtil.global().error(LOG_PREFIX + StrFormatter.format(str, args));
break;
}
}
}
}
@@ -0,0 +1,81 @@
package com.pj.satoken;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoRedissonJackson;
import cn.dev33.satoken.solon.integration.SaTokenInterceptor;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import com.pj.util.AjaxJson;
import cn.dev33.satoken.context.SaHolder;
import org.noear.solon.annotation.Inject;
import org.redisson.api.RedissonClient;
import org.redisson.solon.RedissonSupplier;
/**
* [Sa-Token 权限认证] 配置类
* @author click33
* @author noear
*/
@Configuration
public class SaTokenConfigure {
/**
* 注册 [sa-token全局过滤器]
*/
@Bean(index = -100)
public SaTokenInterceptor tokenPathFilter() {
return new SaTokenInterceptor()
// 指定 [拦截路由] 与 [放行路由]
.addInclude("/**").addExclude("/favicon.ico")
// 认证函数: 每次请求执行
.setAuth(r -> {
// System.out.println("---------- sa全局认证");
// SaRouter.match("/test/test", () -> new Object());
})
// 异常处理函数:每次认证函数发生异常时执行此函数
.setError(e -> {
System.out.println("---------- sa全局异常 ");
return AjaxJson.getError(e.getMessage());
})
// 前置函数:在每次认证函数之前执行(BeforeAuth 不受 includeList 与 excludeList 的限制,所有请求都会进入)
.setBeforeAuth(r -> {
// ---------- 设置一些安全响应头 ----------
SaHolder.getResponse()
// 服务器名称
.setServer("sa-server")
// 是否可以在iframe显示视图: DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
.setHeader("X-Frame-Options", "SAMEORIGIN")
// 是否启用浏览器默认XSS防护: 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时,停止渲染页面
.setHeader("X-Frame-Options", "1; mode=block")
// 禁用浏览器内容嗅探
.setHeader("X-Content-Type-Options", "nosniff")
;
});
}
/**
* 构造 RedissonClient
* */
@Bean
public RedissonClient saTokenDaoInit(@Inject("${sa-token-dao}") RedissonSupplier supplier) {
return supplier.get();
}
/**
* 构建 SaTokenDao
* */
@Bean
public SaTokenDao saTokenDaoInit(RedissonClient redissonClient) {
return new SaTokenDaoRedissonJackson(redissonClient);
}
}
@@ -0,0 +1,44 @@
package com.pj.satoken;
import java.util.ArrayList;
import java.util.List;
import cn.dev33.satoken.stp.StpInterface;
import org.noear.solon.annotation.Component;
/**
* 自定义权限验证接口扩展
*/
@Component // 打开此注解,保证此类被 solon 扫描,即可完成 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;
}
}
@@ -0,0 +1,46 @@
package com.pj.test;
import com.pj.util.AjaxJson;
import cn.dev33.satoken.exception.*;
import org.noear.solon.annotation.Component;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Filter;
import org.noear.solon.core.handle.FilterChain;
/**
* 全局异常处理
*
* @author noear
*/
@Component
public class GlobalExceptionFilter implements Filter {
@Override
public void doFilter(Context ctx, FilterChain chain) throws Throwable {
try {
chain.doFilter(ctx);
} catch (SaTokenException e) {
// 不同异常返回不同状态码
AjaxJson aj = null;
if (e instanceof NotLoginException) { // 如果是未登录异常
NotLoginException ee = (NotLoginException) e;
aj = AjaxJson.getNotLogin().setMsg(ee.getMessage());
} else if (e instanceof NotRoleException) { // 如果是角色异常
NotRoleException ee = (NotRoleException) e;
aj = AjaxJson.getNotJur("无此角色:" + ee.getRole());
} else if (e instanceof NotPermissionException) { // 如果是权限异常
NotPermissionException ee = (NotPermissionException) e;
aj = AjaxJson.getNotJur("无此权限:" + ee.getPermission());
} else if (e instanceof DisableServiceException) { // 如果是被封禁异常
DisableServiceException ee = (DisableServiceException) e;
aj = AjaxJson.getNotJur("账号被封禁:" + ee.getDisableTime() + "秒后解封");
} else { // 普通异常, 输出:500 + 异常信息
aj = AjaxJson.getError(e.getMessage());
}
ctx.render(aj);
}
}
}
@@ -0,0 +1,36 @@
package com.pj.test;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import com.pj.util.AjaxJson;
import cn.dev33.satoken.stp.StpUtil;
import org.noear.solon.annotation.Param;
/**
* 测试: 同域单点登录
* @author click33
* @author noear
*/
@Controller
@Mapping("/sso/")
public class SSOController {
// 测试:进行登录
@Mapping("doLogin")
public AjaxJson doLogin(@Param(defaultValue = "10001") String id) {
System.out.println("---------------- 进行登录 ");
StpUtil.login(id);
return AjaxJson.getSuccess("登录成功: " + id);
}
// 测试:是否登录
@Mapping("isLogin")
public AjaxJson isLogin() {
System.out.println("---------------- 是否登录 ");
boolean isLogin = StpUtil.isLogin();
return AjaxJson.getSuccess("是否登录: " + isLogin);
}
}
@@ -0,0 +1,61 @@
package com.pj.test;
import java.util.ArrayList;
import java.util.List;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import com.pj.util.AjaxJson;
import com.pj.util.Ttime;
import cn.dev33.satoken.stp.StpUtil;
/**
* 压力测试
* @author click33
* @author noear
*/
@Controller
@Mapping("/s-test/")
public class StressTestController {
// 测试 浏览器访问: http://localhost:8081/s-test/login
// 测试前,请先将 is-read-cookie 配置为 false
@Mapping("login")
public AjaxJson login() {
// StpUtil.getTokenSession().logout();
// StpUtil.logoutByLoginId(10001);
int count = 10; // 循环多少轮
int loginCount = 10000; // 每轮循环多少次
// 循环10次 取平均时间
List<Double> list = new ArrayList<>();
for (int i = 1; i <= count; i++) {
System.out.println("\n---------------------第" + i + "轮---------------------");
Ttime t = new Ttime().start();
// 每次登录的次数
for (int j = 1; j <= loginCount; j++) {
StpUtil.login("1000" + j, "PC-" + j);
if(j % 1000 == 0) {
System.out.println("已登录:" + j);
}
}
t.end();
list.add((t.returnMs() + 0.0) / 1000);
System.out.println("" + i + "" + "用时:" + t.toString());
}
// System.out.println(((SaTokenDaoDefaultImpl)SaTokenManager.getSaTokenDao()).dataMap.size());
System.out.println("\n---------------------测试结果---------------------");
System.out.println(list.size() + "次测试: " + list);
double ss = 0;
for (int i = 0; i < list.size(); i++) {
ss += list.get(i);
}
System.out.println("平均用时: " + ss / list.size());
return AjaxJson.getSuccess();
}
}
@@ -0,0 +1,252 @@
package com.pj.test;
import java.util.Date;
import java.util.List;
import com.pj.util.AjaxJson;
import com.pj.util.Ttime;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.session.SaSessionCustomUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import org.noear.snack.ONode;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Param;
/**
* 测试专用Controller
* @author click33
* @author noear
*/
@Controller
@Mapping("/test/")
public class TestController {
// 测试登录接口, 浏览器访问: http://localhost:8081/test/login
@Mapping("login")
public AjaxJson login(@Param(defaultValue="10001") String id) {
System.out.println("======================= 进入方法,测试登录接口 ========================= ");
System.out.println("当前会话的token" + StpUtil.getTokenValue());
System.out.println("当前是否登录:" + StpUtil.isLogin());
System.out.println("当前登录账号:" + StpUtil.getLoginIdDefaultNull());
StpUtil.login(id); // 在当前会话登录此账号
System.out.println("登录成功");
System.out.println("当前是否登录:" + StpUtil.isLogin());
System.out.println("当前登录账号:" + StpUtil.getLoginId());
// System.out.println("当前登录账号并转为int" + StpUtil.getLoginIdAsInt());
System.out.println("当前登录设备:" + StpUtil.getLoginDevice());
// System.out.println("当前token信息:" + StpUtil.getTokenInfo());
return AjaxJson.getSuccess();
}
// 测试退出登录 , 浏览器访问: http://localhost:8081/test/logout
@Mapping("logout")
public AjaxJson logout() {
StpUtil.logout();
// StpUtil.logoutByLoginId(10001);
return AjaxJson.getSuccess();
}
// 测试角色接口, 浏览器访问: http://localhost:8081/test/testRole
@Mapping("testRole")
public AjaxJson testRole() {
System.out.println("======================= 进入方法,测试角色接口 ========================= ");
System.out.println("是否具有角色标识 user " + StpUtil.hasRole("user"));
System.out.println("是否具有角色标识 admin " + StpUtil.hasRole("admin"));
System.out.println("没有admin权限就抛出异常");
StpUtil.checkRole("admin");
System.out.println("在【admin、user】中只要拥有一个就不会抛出异常");
StpUtil.checkRoleOr("admin", "user");
System.out.println("在【admin、user】中必须全部拥有才不会抛出异常");
StpUtil.checkRoleAnd("admin", "user");
System.out.println("角色测试通过");
return AjaxJson.getSuccess();
}
// 测试权限接口, 浏览器访问: http://localhost:8081/test/testJur
@Mapping("testJur")
public AjaxJson testJur() {
System.out.println("======================= 进入方法,测试权限接口 ========================= ");
System.out.println("是否具有权限101" + StpUtil.hasPermission("101"));
System.out.println("是否具有权限user-add" + StpUtil.hasPermission("user-add"));
System.out.println("是否具有权限article-get" + StpUtil.hasPermission("article-get"));
System.out.println("没有user-add权限就抛出异常");
StpUtil.checkPermission("user-add");
System.out.println("在【101、102】中只要拥有一个就不会抛出异常");
StpUtil.checkPermissionOr("101", "102");
System.out.println("在【101、102】中必须全部拥有才不会抛出异常");
StpUtil.checkPermissionAnd("101", "102");
System.out.println("权限测试通过");
return AjaxJson.getSuccess();
}
// 测试会话session接口, 浏览器访问: http://localhost:8081/test/session
@Mapping("session")
public AjaxJson session() {
System.out.println("======================= 进入方法,测试会话session接口 ========================= ");
System.out.println("当前是否登录:" + StpUtil.isLogin());
System.out.println("当前登录账号session的id" + StpUtil.getSession().getId());
System.out.println("当前登录账号session的id" + StpUtil.getSession().getId());
System.out.println("测试取值name" + StpUtil.getSession().get("name"));
StpUtil.getSession().set("name", new Date()); // 写入一个值
System.out.println("测试取值name" + StpUtil.getSession().get("name"));
System.out.println( ONode.stringify(StpUtil.getSession()));
return AjaxJson.getSuccess();
}
// 测试自定义session接口, 浏览器访问: http://localhost:8081/test/session2
@Mapping("session2")
public AjaxJson session2() {
System.out.println("======================= 进入方法,测试自定义session接口 ========================= ");
// 自定义session就是无需登录也可以使用 的session :比如拿用户的手机号当做 key, 来获取 session
System.out.println("自定义 session的id为:" + SaSessionCustomUtil.getSessionById("1895544896").getId());
System.out.println("测试取值name" + SaSessionCustomUtil.getSessionById("1895544896").get("name"));
SaSessionCustomUtil.getSessionById("1895544896").set("name", "张三"); // 写入值
System.out.println("测试取值name" + SaSessionCustomUtil.getSessionById("1895544896").get("name"));
System.out.println("测试取值name" + SaSessionCustomUtil.getSessionById("1895544896").get("name"));
return AjaxJson.getSuccess();
}
// ----------
// 测试token专属session 浏览器访问: http://localhost:8081/test/getTokenSession
@Mapping("getTokenSession")
public AjaxJson getTokenSession() {
System.out.println("======================= 进入方法,测试会话session接口 ========================= ");
System.out.println("当前是否登录:" + StpUtil.isLogin());
System.out.println("当前token专属session: " + StpUtil.getTokenSession().getId());
System.out.println("测试取值name" + StpUtil.getTokenSession().get("name"));
StpUtil.getTokenSession().set("name", "张三"); // 写入一个值
System.out.println("测试取值name" + StpUtil.getTokenSession().get("name"));
return AjaxJson.getSuccess();
}
// 打印当前token信息, 浏览器访问: http://localhost:8081/test/tokenInfo
@Mapping("tokenInfo")
public AjaxJson tokenInfo() {
System.out.println("======================= 进入方法,打印当前token信息 ========================= ");
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
System.out.println(tokenInfo);
return AjaxJson.getSuccessData(tokenInfo);
}
// 测试注解式鉴权, 浏览器访问: http://localhost:8081/test/atCheck
@SaCheckLogin // 注解式鉴权:当前会话必须登录才能通过
@SaCheckRole("super-admin") // 注解式鉴权:当前会话必须具有指定角色标识才能通过
@SaCheckPermission("user-add") // 注解式鉴权:当前会话必须具有指定权限才能通过
@Mapping("atCheck")
public AjaxJson atCheck() {
System.out.println("======================= 进入方法,测试注解鉴权接口 ========================= ");
System.out.println("只有通过注解鉴权,才能进入此方法");
// StpUtil.checkActiveTimeout();
// StpUtil.updateLastActiveToNow();
return AjaxJson.getSuccess();
}
// 测试注解式鉴权, 浏览器访问: http://localhost:8081/test/atJurOr
@Mapping("atJurOr")
@SaCheckPermission(value = {"user-add", "user-all", "user-delete"}, mode = SaMode.OR) // 注解式鉴权:只要具有其中一个权限即可通过校验
public AjaxJson atJurOr() {
return AjaxJson.getSuccessData("用户信息");
}
// [活动时间] 续签: http://localhost:8081/test/rene
@Mapping("rene")
public AjaxJson rene() {
StpUtil.checkActiveTimeout();
StpUtil.updateLastActiveToNow();
return AjaxJson.getSuccess("续签成功");
}
// 测试踢人下线 浏览器访问: http://localhost:8081/test/kickOut
@Mapping("kickOut")
public AjaxJson kickOut() {
// 先登录上
StpUtil.login(10001);
// 踢下线
StpUtil.kickout(10001);
// 再尝试获取
StpUtil.getLoginId();
// 返回
return AjaxJson.getSuccess();
}
// 测试登录接口, 按照设备类型登录, 浏览器访问: http://localhost:8081/test/login2
@Mapping("login2")
public AjaxJson login2(@Param(defaultValue="10001") String id, @Param(defaultValue="PC") String device) {
StpUtil.login(id, device);
return AjaxJson.getSuccess();
}
// 测试身份临时切换: http://localhost:8081/test/switchTo
@Mapping("switchTo")
public AjaxJson switchTo() {
System.out.println("当前会话身份:" + StpUtil.getLoginIdDefaultNull());
System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch());
StpUtil.switchTo(10044, () -> {
System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch());
System.out.println("当前会话身份已被切换为:" + StpUtil.getLoginId());
});
System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch());
return AjaxJson.getSuccess();
}
// 测试会话治理 浏览器访问: http://localhost:8081/test/search
@Mapping("search")
public AjaxJson search() {
System.out.println("--------------");
Ttime t = new Ttime().start();
List<String> tokenValue = StpUtil.searchTokenValue("8feb8265f773", 0, 10, true);
for (String v : tokenValue) {
// SaSession session = StpUtil.getSessionBySessionId(sid);
System.out.println(v);
}
System.out.println("用时:" + t.end().toString());
return AjaxJson.getSuccess();
}
// 测试指定设备类型登录 浏览器访问: http://localhost:8081/test/loginByDevice
@Mapping("loginByDevice")
public AjaxJson loginByDevice() {
System.out.println("--------------");
StpUtil.login(10001, "PC");
return AjaxJson.getSuccessData("登录成功");
}
// 测试 浏览器访问: http://localhost:8081/test/test
@Mapping("test")
public AjaxJson test() {
System.out.println("进来了");
return AjaxJson.getSuccess("访问成功");
}
// 测试 浏览器访问: http://localhost:8081/test/test2
@Mapping("test2")
public AjaxJson test2() {
return AjaxJson.getSuccess();
}
}
@@ -0,0 +1,33 @@
package com.pj.test;
import cn.dev33.satoken.stp.StpUtil;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
/**
* 登录测试
* @author click33
* @author noear
*/
@Controller
@Mapping("/user/")
public class UserController {
// 测试登录,浏览器访问: http://localhost:8081/user/doLogin?username=zhang&password=123456
@Mapping("doLogin")
public String doLogin(String username, String password) {
// 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对
if("zhang".equals(username) && "123456".equals(password)) {
StpUtil.login(10001);
return "登录成功";
}
return "登录失败";
}
// 查询登录状态,浏览器访问: http://localhost:8081/user/isLogin
@Mapping("isLogin")
public String isLogin(String username, String password) {
return "当前会话是否登录:" + StpUtil.isLogin();
}
}
@@ -0,0 +1,162 @@
package com.pj.util;
import java.io.Serializable;
import java.util.List;
/**
* ajax请求返回Json格式数据的封装
*/
public class AjaxJson implements Serializable{
private static final long serialVersionUID = 1L; // 序列化版本号
public static final int CODE_SUCCESS = 200; // 成功状态码
public static final int CODE_ERROR = 500; // 错误状态码
public static final int CODE_WARNING = 501; // 警告状态码
public static final int CODE_NOT_JUR = 403; // 无权限状态码
public static final int CODE_NOT_LOGIN = 401; // 未登录状态码
public static final int CODE_INVALID_REQUEST = 400; // 无效请求状态码
public int code; // 状态码
public String msg; // 描述信息
public Object data; // 携带对象
public Long dataCount; // 数据总数,用于分页
/**
* 返回code
* @return
*/
public int getCode() {
return this.code;
}
/**
* 给msg赋值,连缀风格
*/
public AjaxJson setMsg(String msg) {
this.msg = msg;
return this;
}
public String getMsg() {
return this.msg;
}
/**
* 给data赋值,连缀风格
*/
public AjaxJson setData(Object data) {
this.data = data;
return this;
}
/**
* 将data还原为指定类型并返回
*/
@SuppressWarnings("unchecked")
public <T> T getData(Class<T> cs) {
return (T) data;
}
// ============================ 构建 ==================================
public AjaxJson(int code, String msg, Object data, Long dataCount) {
this.code = code;
this.msg = msg;
this.data = data;
this.dataCount = dataCount;
}
// 返回成功
public static AjaxJson getSuccess() {
return new AjaxJson(CODE_SUCCESS, "ok", null, null);
}
public static AjaxJson getSuccess(String msg) {
return new AjaxJson(CODE_SUCCESS, msg, null, null);
}
public static AjaxJson getSuccess(String msg, Object data) {
return new AjaxJson(CODE_SUCCESS, msg, data, null);
}
public static AjaxJson getSuccessData(Object data) {
return new AjaxJson(CODE_SUCCESS, "ok", data, null);
}
public static AjaxJson getSuccessArray(Object... data) {
return new AjaxJson(CODE_SUCCESS, "ok", data, null);
}
// 返回失败
public static AjaxJson getError() {
return new AjaxJson(CODE_ERROR, "error", null, null);
}
public static AjaxJson getError(String msg) {
return new AjaxJson(CODE_ERROR, msg, null, null);
}
// 返回警告
public static AjaxJson getWarning() {
return new AjaxJson(CODE_ERROR, "warning", null, null);
}
public static AjaxJson getWarning(String msg) {
return new AjaxJson(CODE_WARNING, msg, null, null);
}
// 返回未登录
public static AjaxJson getNotLogin() {
return new AjaxJson(CODE_NOT_LOGIN, "未登录,请登录后再次访问", null, null);
}
// 返回没有权限的
public static AjaxJson getNotJur(String msg) {
return new AjaxJson(CODE_NOT_JUR, msg, null, null);
}
// 返回一个自定义状态码的
public static AjaxJson get(int code, String msg){
return new AjaxJson(code, msg, null, null);
}
// 返回分页和数据的
public static AjaxJson getPageData(Long dataCount, Object data){
return new AjaxJson(CODE_SUCCESS, "ok", data, dataCount);
}
// 返回,根据受影响行数的(大于0=ok,小于0=error)
public static AjaxJson getByLine(int line){
if(line > 0){
return getSuccess("ok", line);
}
return getError("error").setData(line);
}
// 返回,根据布尔值来确定最终结果的 (true=okfalse=error)
public static AjaxJson getByBoolean(boolean b){
return b ? getSuccess("ok") : getError("error");
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@SuppressWarnings("rawtypes")
@Override
public String toString() {
String data_string = null;
if(data == null){
} else if(data instanceof List){
data_string = "List(length=" + ((List)data).size() + ")";
} else {
data_string = data.toString();
}
return "{"
+ "\"code\": " + this.getCode()
+ ", \"msg\": \"" + this.getMsg() + "\""
+ ", \"data\": " + data_string
+ ", \"dataCount\": " + dataCount
+ "}";
}
}
@@ -0,0 +1,63 @@
package com.pj.util;
/**
* 用于测试用时
* @author click33
*
*/
public class Ttime {
private long start=0; //开始时间
private long end=0; //结束时间
public static Ttime t = new Ttime(); //static快捷使用
/**
* 开始计时
* @return
*/
public Ttime start() {
start=System.currentTimeMillis();
return this;
}
/**
* 结束计时
*/
public Ttime end() {
end=System.currentTimeMillis();
return this;
}
/**
* 返回所用毫秒数
*/
public long returnMs() {
return end-start;
}
/**
* 格式化输出结果
*/
public void outTime() {
System.out.println(this.toString());
}
/**
* 结束并格式化输出结果
*/
public void endOutTime() {
this.end().outTime();
}
@Override
public String toString() {
return (returnMs() + 0.0) / 1000 + "s"; // 格式化为:0.01s
}
}
@@ -0,0 +1,32 @@
# 端口
server:
port: 8081
# sa-token 配置
sa-token:
# token 名称 (同时也是 cookie 名称)
token-name: satoken
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
timeout: 2592000
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
active-timeout: -1
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
is-share: true
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik
token-style: uuid
# 是否输出操作日志
is-log: true
sa-token-dao:
config: |
singleServerConfig:
password: "123456"
address: "redis://localhost:6379"
database: 0
+5 -15
View File
@@ -10,14 +10,13 @@
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.2.3</version>
<version>2.4.0</version>
<relativePath/>
</parent>
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<solon.version>2.2.3</solon.version>
<sa-token.version>1.36.0</sa-token.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
@@ -28,13 +27,11 @@
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-web</artifactId>
<version>${solon.version}</version>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon.logging</artifactId>
<version>${solon.version}</version>
<artifactId>solon.logging.simple</artifactId>
</dependency>
<!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc/ -->
@@ -45,18 +42,11 @@
</dependency>
<!-- sa-token整合redis (使用jdk默认序列化方式) -->
<!-- <dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisx</artifactId>
<version>${sa-token.version}</version>
</dependency> -->
<!-- 提供redis连接池 -->
<!-- <dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency> -->
</dependency>
<!-- hutool工具类,用来生成雪花算法唯一id -->
<!-- <dependency>
@@ -1,14 +1,16 @@
package com.pj.satoken;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoOfRedis;
import cn.dev33.satoken.solon.integration.SaTokenInterceptor;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import com.pj.util.AjaxJson;
import cn.dev33.satoken.context.SaHolder;
import org.noear.solon.annotation.Inject;
/**
@@ -57,4 +59,9 @@ public class SaTokenConfigure {
;
});
}
//如果需要 redis dao,加这段代表
// @Bean
// public SaTokenDao saTokenDaoInit(@Inject("${sa-token-dao.redis}") SaTokenDaoOfRedis saTokenDao) {
// return saTokenDao;
// }
}
@@ -18,31 +18,14 @@ sa-token:
token-style: uuid
# 是否输出操作日志
is-log: true
solon:
# redis配置
sa-token-dao: #名字可以随意取
redis:
# Redis数据库索引(默认为0
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间(毫秒)
timeout: 10000ms
lettuce:
pool:
# 连接池最大连接数
max-active: 200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# 连接池中的最大空闲连接
max-idle: 10
# 连接池中的最小空闲连接
min-idle: 0
server: "localhost:6379"
password: 123456
db: 1
maxTotal: 200
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -10,13 +10,13 @@
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.2.3</version>
<version>2.4.0</version>
<relativePath/>
</parent>
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
<solon.version>2.2.3</solon.version>
</properties>
@@ -10,13 +10,13 @@
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.2.3</version>
<version>2.4.0</version>
<relativePath/>
</parent>
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -10,13 +10,13 @@
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.2.3</version>
<version>2.4.0</version>
<relativePath/>
</parent>
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -10,13 +10,13 @@
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.2.3</version>
<version>2.4.0</version>
<relativePath/>
</parent>
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
+2 -2
View File
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
<java.run.main.class>com.pj.SaTokenApplication</java.run.main.class>
</properties>
@@ -72,7 +72,7 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<!-- 构建配置 -->
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
+1 -1
View File
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.35.0.RC</sa-token.version>
<sa-token.version>1.36.0</sa-token.version>
</properties>
<dependencies>
+10 -4
View File
@@ -12,7 +12,7 @@
<description>Sa-Token Dependencies</description>
<properties>
<revision>1.35.0.RC</revision>
<revision>1.36.0</revision>
<!-- 统一定义依赖版本号 -->
<springboot.version>2.5.15</springboot.version>
@@ -23,9 +23,9 @@
<servlet-api.version>3.1.0</servlet-api.version>
<jakarta-servlet-api.version>6.0.0</jakarta-servlet-api.version>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<solon.version>2.2.3</solon.version>
<noear-redisx.version>1.4.7</noear-redisx.version>
<noear-snack3.version>3.2.65</noear-snack3.version>
<solon.version>2.5.3</solon.version>
<noear-redisx.version>1.4.8</noear-redisx.version>
<noear-snack3.version>3.2.79</noear-snack3.version>
<jfinal.version>4.9.17</jfinal.version>
<jboot.version>3.14.4</jboot.version>
<commons-pool2.version>2.5.0</commons-pool2.version>
@@ -140,6 +140,12 @@
</dependency>
<!-- Redisson 相关操作API -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
+2 -14
View File
@@ -1,7 +1,7 @@
<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.35.0.RC</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.36.0</h1>
<h5 align="center">一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!</h5>
<p align="center" class="badge-box">
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg?theme=gvp"></a>
@@ -136,18 +136,6 @@ Sa-Token 目前主要五大功能模块:登录认证、权限认证、单点
## 交流群
QQ交流群:707350988 [点击加入](https://jq.qq.com/?_wv=1027&k=tqbzHT2D)
加入 Sa-Token 框架 QQ、微信讨论群:[点击加入](/more/join-group.md)
微信交流群:
![微信群](https://dev33-test.oss-cn-beijing.aliyuncs.com/sa-token/i-wx-qr.png ':size=230')
(扫码添加微信,备注:sa-token,邀您加入群聊)
<br>
加入群聊的好处:
- 第一时间收到框架更新通知。
- 第一时间收到框架 bug 通知。
- 第一时间收到新增开源案例通知。
- 和众多大佬一起互相 (huá shǔi) 交流 (mō yú)。
+57 -10
View File
@@ -18,7 +18,7 @@
<div class="logo-box">
<img src="logo.png" title="logo" />
<h1 class="logo-text">Sa-Token</h1>
<sub>v1.35.0.RC</sub>
<sub>v1.36.0</sub>
</div>
</a>
</div>
@@ -28,6 +28,7 @@
</div>
<select class="select-version p-none" onchange="location.href=this.value">
<option value="doc.html">最新版</option>
<option value="v/v1.35.0/doc.html">v1.35.0</option>
<option value="v/v1.34.0/doc.html">v1.34.0</option>
<option value="v/v1.33.0/doc.html">v1.33.0</option>
<option value="v/v1.32.0/doc.html">v1.32.0</option>
@@ -102,7 +103,7 @@
<!-- <a class="p-none wzi" href="#/more/blog">博客</a> -->
<a class="p-none wzi" href="#/more/join-group">加入讨论群</a>
<a class="p-none wzi" href="#/more/sa-token-donate">赞助</a>
<a class="p-none wzi" href="#/sso/sso-pro">🔥 SSO商业版</a>
<a class="p-none wzi" href="#/sso/sso-pro">?? SSO商业版</a>
<div class="zk-box">
<a class="wzi" href="javascript:;">
<span>相关资源 </span>
@@ -136,10 +137,21 @@
<div class="main-box">
<div id="app">加载中...</div>
</div>
<!-- 万维广告div -->
<div style="position: fixed; right: 0; bottom: 0; z-index: 10000; border: 0px #aaa solid;">
<div class="wwads-cn wwads-vertical" data-id="88" style="max-width:150px"></div>
</div>
<!-- 小助手div -->
<div class="p-none help-btn-box" style="position: fixed; right: 40px; bottom: 330px; z-index: 10000; border: 0px #aaa solid;">
<div class="help-tips" style="position: relative; left: -30px; top: -10px;"></div>
<div class="help-btn" style="width: 60px; height: 60px; text-align: center; border-radius: 50%; background-color: #42b983; cursor: pointer;">
<span style="font-size: 18px; color: #FFF; line-height: 60px;">Help</span>
</div>
</div>
<!-- UI逐渐显现 -->
<style type="text/css">
body{opacity: 0.01; transition: opacity 0.5s; background-color: #FFF;}
@@ -151,9 +163,10 @@
</script>
<!-- -->
<script src="./static/docsify-plugin.js"></script>
<script src="./static/docsify-plugin.js?v=6"></script>
<script src="./static/is-star-plugin.js?v=6"></script>
<script>
var saTokenTopVersion = '1.35.0.RC'; // Sa-Token最新版本
var saTokenTopVersion = '1.36.0'; // Sa-Token最新版本
var name = '<img style="width: 60px; height: 60px; vertical-align: middle;" src="logo.png" alt="logo" /> ';
name += '<b style="font-size: 28px; vertical-align: middle;">Sa-Token</b> <sub>v' + saTokenTopVersion + '</sub>';
window.$docsify = {
@@ -187,7 +200,7 @@
tabHeadings: true // 用标题+粗体来定制选项卡
},
// 自定义插件
plugins: [myDocsifyPlugin],
plugins: [myDocsifyPlugin, window.isStarPlugin],
}
</script>
<script src="static/docsify.min.js"></script>
@@ -236,12 +249,9 @@
})();
</script>
<script type="text/javascript" src="https://cdn.wwads.cn/js/makemoney.js" async></script>
<!-- 万维广告 -->
<script data-mode="hash" type="text/javascript" src="https://cdn.wwads.cn/js/makemoney.js" async></script>
<!-- 友盟 -->
<div style="height: 0px; overflow: hidden;">
<script type="text/javascript" src="https://s4.cnzz.com/z_stat.php?id=1279646043&web_id=1279646043"></script>
</div>
<!-- 百度统计 -->
<script>
var _hmt = _hmt || [];
@@ -261,6 +271,43 @@
}
</script>
<!-- 小助手提示 -->
<script>
$('.help-btn').click(function(){
var str = `
<div class="xiaozhushou-intro">
<p>1、你在使用 Sa-Token 时遇到任何技术难题,可以向 < sa-token 小助手 > 求助咨询。</p>
<p>2、该小助手不属于商业运营,求助咨询完全免费。</p>
<p>3、目前该小助手属于试运营阶段,每天只能提供大约 1 小时的求助时间。</p>
<p>4、根据运营效果反馈,我们日后可能会提高求助时间,但也可能关闭此功能。</p>
<p>5、该小助手由企业微信提供平台支持,感谢企业微信。</p>
<p>6、不是 AI 是真人,不是 AI 是真人,不是 AI 是真人,重说三!</p>
<p style="margin-top: 30px;">打开方式:</p>
<p>1、如果你是使用 PC 端微信,请点此链接:<a href="https://work.weixin.qq.com/kfid/kfcdd45c432fee9655f" target="_blank">https://work.weixin.qq.com/kfid/kfcdd45c432fee9655f</a></p>
<p>2、如果你是使用手机端微信,请扫码:</p>
<p><img src="https://oss.dev33.cn/sa-token/sa-token-xiaozhushou.jpg" width="200px"></p>
</div>
`;
layer.alert(str, {
title: '技术求助',
area: '550px',
offset: '10%',
})
})
try{
// 给个小提示
const index = layer.tips('框架技术支持,点此求助', '.help-tips', {
tips: [1, '#000'] ,//还可配置颜色
time: 5000,
});
// 改为 fixed 定位,否则它会随着滚动条移动,样式就跑偏了
$('#layui-layer' + index).css('position', 'fixed');
}catch(e){
console.error(e);
}
</script>
<!-- 修改背景颜色 -->
<script>
+2
View File
@@ -1,5 +1,7 @@
# Sa-Token 插件开发指南
> 注:为 Sa-Token 提交插件请在 sa-token-three-plugin 仓库进行:[点击跳转](https://gitee.com/sa-tokens/sa-token-three-plugin)
---
插件,从字面意思理解就是可拔插的组件,作用是在不改变 Sa-Token 现有架构的情况下,替换或扩展一部分底层代码逻辑。
+341 -176
View File
@@ -4,16 +4,20 @@
<meta charset="UTF-8">
<title>Sa-Token</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Sa-Token是一个java权限认证框架,功能全面,上手简单,登录认证、权限认证、Session会话、踢人下线、账号封禁、集成Redis、前后端分离、分布式会话、微服务网关鉴权、单点登录、OAuth2.0、临时Token验证、记住我模式、模拟他人账号、临时身份切换、多账号体系、注解式鉴权、路由拦截式鉴权、花式token、自动续签、同端互斥登录、会话治理、密码加密、jwt集成、Spring集成、WebFlux集成...,有了sa-token,你所有的权限认证问题,都不再是问题">
<meta name="description"
content="Sa-Token是一个java权限认证框架,功能全面,上手简单,登录认证、权限认证、Session会话、踢人下线、账号封禁、集成Redis、前后端分离、分布式会话、微服务网关鉴权、单点登录、OAuth2.0、临时Token验证、记住我模式、模拟他人账号、临时身份切换、多账号体系、注解式鉴权、路由拦截式鉴权、花式token、自动续签、同端互斥登录、会话治理、密码加密、jwt集成、Spring集成、WebFlux集成...,有了sa-token,你所有的权限认证问题,都不再是问题">
<meta name="keywords" content="sa-token,sa-token框架,sa-token文档,java权限认证">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="shortcut icon" type="image/x-icon" href="logo.png">
<link rel="stylesheet" href="static/index.css">
<link rel="stylesheet" href="static/swiper/swiper-bundle.min.css">
<link rel="stylesheet" href="static/swiper/index-swiper.css">
</head>
<body>
<!-- 总盒子 -->
<div class="z-div" style="">
<div class="z-div" style="">
<!-- ------------ 头部 ------------- -->
<header class="doc-header">
<div class="nav-left">
@@ -41,13 +45,13 @@
<span style="background-color: #F1FAFA;"></span>
<span style="background-color: #f5f5d5;"></span>
<span style="background-color: #d5f5f5;"></span>
<span style="background-color: #f5e5f5;"></span>
<span style="background-color: #E8E8FF;"></span>
<span style="background-color: #f0f9eb;"></span>
<span style="background-color: #ebe5dd;"></span>
<span style="background-color: #e8f4ff;"></span>
<!-- <span style="background-color: #F0DAD2;"></span> -->
<!-- <span style="background-color: #f5d5d5;"></span> -->
<!-- <span style="background-color: #FFFFE0;"></span> -->
@@ -63,7 +67,7 @@
<!-- <a class="p-none wzi" href="doc.html#/more/blog">博客</a> -->
<a class="p-none wzi" href="doc.html#/more/join-group">加入讨论群</a>
<a class="p-none wzi" href="doc.html#/more/sa-token-donate">赞助</a>
<a class="p-none wzi" href="doc.html#/sso/sso-pro">🔥 SSO商业版</a>
<a class="p-none wzi" href="doc.html#/sso/sso-pro">?? SSO商业版</a>
<div class="zk-box">
<a class="wzi" href="javascript:;">
<span>相关资源 </span>
@@ -86,24 +90,26 @@
</div>
</div>
<!-- github小章鱼图标 -->
<a href="https://github.com/dromara/sa-token" target="_blank" class="github-corner" aria-label="View source on Github"
style="position: fixed; right: -16px; padding-left: 0px;">
<a href="https://github.com/dromara/sa-token" target="_blank" class="github-corner"
aria-label="View source on Github" style="position: fixed; right: -16px; padding-left: 0px;">
<svg viewBox="0 0 250 250" aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="currentColor" class="octo-body"></path>
<path
d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
<path
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="currentColor" class="octo-body"></path>
</svg>
</a>
</nav>
</header>
<!-- ------------ 海报部分 ------------- -->
<div class="main-box">
<div class="content-box">
<!-- <div class="fenge"></div> -->
<h1>Sa-Token<small>v1.35.0.RC</small></h1>
<h1>Sa-Token<small>v1.36.0</small></h1>
<div class="sub-title">一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!</div>
<div class="btn-box">
<a class="abtn" href="https://github.com/dromara/sa-token" target="_blank">GitHub</a>
@@ -113,17 +119,24 @@
<!-- <a href="https://gitee.com/dromara/sa-token" target="_blank">集成案例</a> -->
</div>
<h4 align="center" class="badge-box">
<a href="https://gitee.com/dromara/sa-token/stargazers"><img class="lazy" data-original="https://gitee.com/dromara/sa-token/badge/star.svg?theme=gvp"></a>
<a href="https://gitee.com/dromara/sa-token/members"><img class="lazy" data-original="https://gitee.com/dromara/sa-token/badge/fork.svg?theme=gvp"></a>
<a href="https://github.com/dromara/sa-token/stargazers"><img class="lazy" data-original="https://img.shields.io/github/stars/dromara/sa-token?style=flat-square&logo=GitHub"></a>
<a href="https://github.com/dromara/sa-token/network/members"><img class="lazy" data-original="https://img.shields.io/github/forks/dromara/sa-token?style=flat-square&logo=GitHub"></a>
<a href="https://github.com/dromara/sa-token/watchers"><img class="lazy" data-original="https://img.shields.io/github/watchers/dromara/sa-token?style=flat-square&logo=GitHub"></a>
<a href="https://github.com/dromara/sa-token/issues"><img class="lazy" data-original="https://img.shields.io/github/issues/dromara/sa-token.svg?style=flat-square&logo=GitHub"></a>
<a href="https://github.com/dromara/sa-token/blob/master/LICENSE"><img class="lazy" data-original="https://img.shields.io/github/license/dromara/sa-token.svg?style=flat-square"></a>
<a href="https://gitee.com/dromara/sa-token/stargazers"><img class="lazy"
data-original="https://gitee.com/dromara/sa-token/badge/star.svg?theme=gvp"></a>
<a href="https://gitee.com/dromara/sa-token/members"><img class="lazy"
data-original="https://gitee.com/dromara/sa-token/badge/fork.svg?theme=gvp"></a>
<a href="https://github.com/dromara/sa-token/stargazers"><img class="lazy"
data-original="https://img.shields.io/github/stars/dromara/sa-token?style=flat-square&logo=GitHub"></a>
<a href="https://github.com/dromara/sa-token/network/members"><img class="lazy"
data-original="https://img.shields.io/github/forks/dromara/sa-token?style=flat-square&logo=GitHub"></a>
<a href="https://github.com/dromara/sa-token/watchers"><img class="lazy"
data-original="https://img.shields.io/github/watchers/dromara/sa-token?style=flat-square&logo=GitHub"></a>
<a href="https://github.com/dromara/sa-token/issues"><img class="lazy"
data-original="https://img.shields.io/github/issues/dromara/sa-token.svg?style=flat-square&logo=GitHub"></a>
<a href="https://github.com/dromara/sa-token/blob/master/LICENSE"><img class="lazy"
data-original="https://img.shields.io/github/license/dromara/sa-token.svg?style=flat-square"></a>
</h4>
</div>
</div>
<!-- ------------ 支持特性 ------------- -->
<div>
<div class="feature-z s-width">
@@ -134,7 +147,7 @@
<p>多端登录、单端登录、同端互斥登录、七天免登录…… 多种登录策略只需改个配置即可完成</p>
</div>
<div class="feature">
<h2>🔑 权限认证</h2>
<h2>?? 权限认证</h2>
<p>权限认证、角色认证、会话二级认证、注解鉴权、路由鉴权……多种姿势灵活鉴权</p>
</div>
<div class="feature">
@@ -142,27 +155,27 @@
<p>强制注销、踢人下线、账号封禁、身份切换、自动续签 …… 提供完善的会话管理方案</p>
</div>
<div class="feature">
<h2>🔎 Redis集成</h2>
<h2>?? Redis集成</h2>
<p>提供 Redis 集成方案、项目重启数据不丢失、多系统数据互通,可自定义数据持久化策略</p>
</div>
<div class="feature">
<h2>🚀 前后端分离</h2>
<h2>?? 前后端分离</h2>
<p>内置多种 Token 读取策略,适配APP、小程序、SPA单页应用等前后端分离场景</p>
</div>
<div class="feature">
<h2>🍃 单点登录</h2>
<h2>?? 单点登录</h2>
<p>同域、跨域、共享Redis、跨Redis、前后端一体、前后端分离……提供各种架构下的SSO接入方案</p>
</div>
<div class="feature">
<h2>🍂 OAuth2.0</h2>
<h2>?? OAuth2.0</h2>
<p>轻松搭建 OAuth2.0 认证中心,支持四种授权模式,支持 openid 授权机制,支持二次扩展开发</p>
</div>
<div class="feature">
<h2>💦 微服务支持</h2>
<h2>?? 微服务支持</h2>
<p>分布式 Session 会话、网关统一鉴权、RPC调用鉴权……提供开箱即用的微服务认证方案</p>
</div>
<div class="feature">
<h2>🗳 开箱即用</h2>
<h2>?? 开箱即用</h2>
<p>提供SpringMVC、WebFlux、Solon、jwt 等常见框架集成包,真正的开箱即用……</p>
</div>
</div>
@@ -172,14 +185,55 @@
</div>
</div>
</div>
<!-- ------------ 曾获荣誉 ------------- -->
<div>
<div class="feature-z ry-kuai">
<div class="s-fenge"></div>
<h2 class="s-title">曾获荣誉</h2>
<div class="ry-box">
<div class="swiper mySwiper">
<div class="swiper-wrapper">
<div class="swiper-slide">
<img src="https://oss.dev33.cn/sa-token/awards/gpv.jpg?x-oss-process=style/st" /> <br>
<p>GVP - Gitee 最有价值开源项目</p>
</div>
<div class="swiper-slide">
<img src="https://oss.dev33.cn/sa-token/awards/osc-2021.jpg?x-oss-process=style/st"/> <br>
<p>OSCHINA 2021 人气指数 TOP 30 开源项目</p>
</div>
<div class="swiper-slide swiper-slide-tx1">
<img src="https://oss.dev33.cn/sa-token/awards/osc-2022.jpg?x-oss-process=style/st" /> <br>
<p>OSCHINA 2022 年度最火热中国开源项目社区</p>
</div>
<div class="swiper-slide">
<img src="https://oss.dev33.cn/sa-token/awards/kexin.jpg?x-oss-process=style/st" /> <br>
<p>可信开源社区共同体预备成员</p>
</div>
<!-- <div class="swiper-slide" style="width: 750px;">
<img src="https://oss.dev33.cn/sa-token/awards/gitee-star-10k.png" /> <br>
<p>Gitee stars 超 10k+</p>
</div>
<div class="swiper-slide" style="width: 750px;">
<img src="https://oss.dev33.cn/sa-token/awards/github-star-10k.png" /> <br>
<p>GitHub stars 超 10k+</p>
</div> -->
</div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
</div>
<!-- ------------ 开源案例 ------------- -->
<div>
<div class="feature-z s-width">
<div class="s-fenge"></div>
<h2 class="s-title">优秀开源集成案例</h2>
<!-- <div class="s-fenge"></div> -->
<h2 class="s-title" style="margin-top: 40px;">优秀开源集成案例</h2>
<div class="feature-box s-case-box">
<!-- Snowy 5.5k -->
<!-- Snowy 6.1K -->
<div class="s-case">
<a href="https://gitee.com/xiaonuobase/snowy" target="_blank" class="s-case-link">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/case/case--snowy.png">
@@ -188,34 +242,37 @@
<span class="s-author"> 小诺开源技术 </span>
<p class="s-case-intro">国内首个国密前后分离快速开发平台,基于Vue3、Antdv、SaToken</p>
</div>
<!-- SpringBoot_v2 5.3k -->
<div class="s-case">
<a href="https://gitee.com/bdj/SpringBoot_v2" target="_blank" class="s-case-link">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/case/case--springboot_v2.png">
</a>
<h3 class="s-case-title">SpringBoot_v2</h3>
<span class="s-author">开源oschina</span>
<p class="s-case-intro">努力打造 springboot 框架的极致细腻的脚手架,原生纯净。</p>
</div>
<!-- RuoYi-Vue-Plus 4.1k -->
<!-- RuoYi-Vue-Plus 5.9k -->
<div class="s-case">
<a href="https://gitee.com/dromara/RuoYi-Vue-Plus" target="_blank" class="s-case-link">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/case/case--ruoyi-vue-plus.png">
<img class="lazy"
data-original="https://oss.dev33.cn/sa-token/case/case--ruoyi-vue-plus.png">
</a>
<h3 class="s-case-title">RuoYi-Vue-Plus</h3>
<span class="s-author"> 疯狂的狮子Li </span>
<p class="s-case-intro">重写 RuoYi-Vue 所有功能,集成 Sa-Token、Mybatis-Plus、Hutool 定期同步</p>
</div>
<!-- RuoYi-Cloud-Plus 1.5K -->
<!-- SpringBoot_v2 5.5k -->
<div class="s-case">
<a href="https://gitee.com/bdj/SpringBoot_v2" target="_blank" class="s-case-link">
<img class="lazy"
data-original="https://oss.dev33.cn/sa-token/case/case--springboot_v2.png">
</a>
<h3 class="s-case-title">SpringBoot_v2</h3>
<span class="s-author">开源oschina</span>
<p class="s-case-intro">努力打造 springboot 框架的极致细腻的脚手架,原生纯净。</p>
</div>
<!-- RuoYi-Cloud-Plus 2.4K -->
<div class="s-case">
<a href="https://gitee.com/dromara/RuoYi-Cloud-Plus" target="_blank" class="s-case-link">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/case/case--ruoyi-cloud-plus.png">
<img class="lazy"
data-original="https://oss.dev33.cn/sa-token/case/case--ruoyi-cloud-plus.png">
</a>
<h3 class="s-case-title">RuoYi-Cloud-Plus</h3>
<span class="s-author"> 疯狂的狮子Li </span>
<p class="s-case-intro">重写 RuoYi-Cloud 所有功能 整合 SpringCloudAlibaba、Dubbo3.0、Sa-Token</p>
</div>
<!-- Sa-Plus 1K -->
<!-- Sa-Plus 1.1K -->
<div class="s-case">
<a href="https://gitee.com/click33/sa-plus" target="_blank" class="s-case-link">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/case/case--sa-plus.png">
@@ -224,10 +281,11 @@
<span class="s-author"> 孔明 </span>
<p class="s-case-intro">一个基于 SpringBoot 的快速开发框架,内置代码生成器</p>
</div>
<!-- EasyAdmin 878 -->
<!-- EasyAdmin 996 -->
<div class="s-case">
<a href="https://gitee.com/lakernote/easy-admin" target="_blank" class="s-case-link">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/case/case--easy-admin.png">
<img class="lazy"
data-original="https://oss.dev33.cn/sa-token/case/case--easy-admin.png">
</a>
<h3 class="s-case-title">EasyAdmin</h3>
<span class="s-author"> laker </span>
@@ -237,14 +295,20 @@
<div class="re-text">
<span>
如果您的开源项目也使用了 Sa-Token,您可以
<a href="https://gitee.com/sa-token/awesome-sa-token" target="_blank" style="text-decoration: none;">在此</a>
<a href="https://gitee.com/sa-token/awesome-sa-token" target="_blank"
style="text-decoration: none;">在此</a>
提交
</span>
</div>
<div style=" margin: 40px 14px 0; padding: 20px 0 10px; background-color: #f4f5f7;">
<h3 style="padding: 5px 0 20px; color: #333;">Sa-Token 官方公众号,及时接收框架更新通知、技术文章</h3>
<img class="lazy gzh-qr" data-original="https://oss.dev33.cn/sa-token/lykj-gzh.jpg" style="width: 150px; cursor: pointer;">
</div>
</div>
</div>
<!-- ------------ 使用公司 ------------- -->
<div>
<div class="com-box-f s-width">
@@ -312,7 +376,8 @@
<a href="javascript:;" title="辽宁薪达网络科技有限公司">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/com/taipingyangcanyin.png">
</a>
<a href="https://www.pactera.com/?renqun_youhua=2483561&bd_vid=9062916023494825120" target="_blank" title="中电文思海辉">
<a href="https://www.pactera.com/?renqun_youhua=2483561&bd_vid=9062916023494825120"
target="_blank" title="中电文思海辉">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/com/zhongdianwensi-logo.png">
</a>
<a href="https://tisiqikeji.com/" target="_blank" title="吉林省体思奇健康科技有限公司">
@@ -354,18 +419,28 @@
<a href="https://www.zhongyuankeji.cn/" target="_blank" title="山东众远信息科技有限公司">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/com/zhongyuankeji.png">
</a>
<a href="https://xmnk.cn/" target="_blank" title="希梦耐康网络科技">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/com/ximengnaikang.png">
</a>
<a href="https://hxp.liuxin.online/" target="_blank" title="沪小漂">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/com/hero.png">
</a>
<a href="https://www.mall4j.com/" target="_blank" title="广州市蓝海创新科技有限公司">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/com/guangzhoulanhai.png">
</a>
</div>
<div style="height: 10px; clear: both;"></div>
<p>
(如果您的企业也使用了 Sa-Token,您可以
<a href="https://gitee.com/dromara/sa-token/issues/I3EV1M" target="_blank" style="text-decoration: none;">在此</a>
<a href="https://gitee.com/dromara/sa-token/issues/I3EV1M" target="_blank"
style="text-decoration: none;">在此</a>
提交)
</p>
</div>
<div style="height: 60px;"></div>
</div>
<!-- ------------ Dromara 成员项目 ------------- -->
<div>
<div class="com-box-f s-width">
@@ -376,131 +451,199 @@
</h2>
<div class="com-box com-box-you">
<a href="https://gitee.com/dromara/TLog" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/tlog.png" msg="一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/tlog.png"
msg="一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪">
</a>
<a href="https://gitee.com/dromara/liteFlow" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/liteflow.png" msg="轻量,快速,稳定,可编排的组件式流程引擎">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/liteflow.png"
msg="轻量,快速,稳定,可编排的组件式流程引擎">
</a>
<a href="https://hutool.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hutool.jpg" msg="🍬小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hutool.jpg"
msg="??小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。">
</a>
<a href="https://sa-token.cc/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sa-token.png" msg="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sa-token.png"
msg="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!">
</a>
<a href="https://gitee.com/dromara/hmily" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hmily.png" msg="高性能一站式分布式事务解决方案。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hmily.png"
msg="高性能一站式分布式事务解决方案。">
</a>
<a href="https://gitee.com/dromara/Raincat" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/raincat.png" msg="强一致性分布式事务解决方案。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/raincat.png"
msg="强一致性分布式事务解决方案。">
</a>
<a href="https://gitee.com/dromara/myth" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/myth.png" msg="可靠消息分布式事务解决方案。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/myth.png"
msg="可靠消息分布式事务解决方案。">
</a>
<a href="https://cubic.jiagoujishu.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/cubic.png" msg="一站式问题定位平台,以agent的方式无侵入接入应用,完整集成arthas功能模块,致力于应用级监控,帮助开发人员快速定位问题">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/cubic.png"
msg="一站式问题定位平台,以agent的方式无侵入接入应用,完整集成arthas功能模块,致力于应用级监控,帮助开发人员快速定位问题">
</a>
<a href="https://maxkey.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/maxkey.png" msg="业界领先的身份管理和认证产品">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/maxkey.png"
msg="业界领先的身份管理和认证产品">
</a>
<a href="http://forest.dtflyx.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/forest-logo.png" msg="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" nf>
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/forest-logo.png"
msg="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" nf>
</a>
<a href="https://jpom.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/jpom.png" msg="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/jpom.png"
msg="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件">
</a>
<a href="https://su.usthe.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sureness.png" msg="面向 REST API 的高性能认证鉴权框架">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sureness.png"
msg="面向 REST API 的高性能认证鉴权框架">
</a>
<a href="https://easy-es.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/easy-es2.png" msg="🚀傻瓜级ElasticSearch搜索引擎ORM框架">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/easy-es2.png"
msg="??傻瓜级ElasticSearch搜索引擎ORM框架">
</a>
<a href="https://gitee.com/dromara/northstar" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/northstar_logo.png" msg="Northstar盈富量化交易平台">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/northstar_logo.png"
msg="Northstar盈富量化交易平台">
</a>
<a href="https://hertzbeat.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hertzbeat-brand.svg" msg="易用友好的云监控系统">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hertzbeat-brand.svg"
msg="易用友好的云监控系统">
</a>
<a href="https://dromara.gitee.io/fast-request/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/fast-request.gif" msg="Idea 版 Postman,为简化调试API而生">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/fast-request.gif"
msg="Idea 版 Postman,为简化调试API而生">
</a>
<a href="https://www.jeesuite.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mendmix.png" msg="开源分布式云原生架构一站式解决方案">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mendmix.png"
msg="开源分布式云原生架构一站式解决方案">
</a>
<a href="https://gitee.com/dromara/koalas-rpc" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/koalas-rpc2.png" msg="企业生产级百亿日PV高可用可拓展的RPC框架。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/koalas-rpc2.png"
msg="企业生产级百亿日PV高可用可拓展的RPC框架。">
</a>
<a href="https://async.sizegang.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/gobrs-async.png" msg="🔥 配置极简功能强大的异步任务动态编排框架">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/gobrs-async.png"
msg="?? 配置极简功能强大的异步任务动态编排框架">
</a>
<a href="https://dynamictp.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dynamic-tp.png" msg="🔥🔥🔥 基于配置中心的轻量级动态可监控线程池">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dynamic-tp.png"
msg="?????? 基于配置中心的轻量级动态可监控线程池">
</a>
<a href="https://www.x-easypdf.cn" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/x-easypdf.png" msg="一个用搭积木的方式构建pdf的框架(基于pdfbox">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/x-easypdf.png"
msg="一个用搭积木的方式构建pdf的框架(基于pdfbox">
</a>
<a href="http://dromara.gitee.io/image-combiner" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/image-combiner.png" msg="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/image-combiner.png"
msg="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大">
</a>
<a href="https://www.herodotus.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dante-cloud2.png" msg="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dante-cloud2.png"
msg="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。">
</a>
<a href="http://www.mtruning.club" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/go-view.png" msg="低代码数据可视化开发平台">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/go-view.png"
msg="低代码数据可视化开发平台">
</a>
<a href="https://tangyh.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/lamp-cloud.png" msg="微服务中后台快速开发平台,支持租户(SaaS)模式、非租户模式">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/lamp-cloud.png"
msg="微服务中后台快速开发平台,支持租户(SaaS)模式、非租户模式">
</a>
<a href="https://www.redisfront.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/redis-front.png" msg="RedisFront 是一款开源免费的跨平台 Redis 桌面客户端工具, 支持单机模式, 集群模式, 哨兵模式以及 SSH 隧道连接, 可轻松管理Redis缓存数据.">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/redis-front.png"
msg="RedisFront 是一款开源免费的跨平台 Redis 桌面客户端工具, 支持单机模式, 集群模式, 哨兵模式以及 SSH 隧道连接, 可轻松管理Redis缓存数据.">
</a>
<a href="https://www.yuque.com/u34495/mivcfg" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/electron-egg.png" msg="一个入门简单、跨平台、企业级桌面软件开发框架">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/electron-egg.png"
msg="一个入门简单、跨平台、企业级桌面软件开发框架">
</a>
<a href="https://gitee.com/dromara/open-capacity-platform" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/open-capacity-platform.jpg" msg="简称ocp是基于Spring Cloud的企业级微服务框架(用户权限管理,配置中心管理,应用管理,....)">
<img class="lazy"
data-original="https://oss.dev33.cn/sa-token/link/open-capacity-platform.jpg"
msg="简称ocp是基于Spring Cloud的企业级微服务框架(用户权限管理,配置中心管理,应用管理,....)">
</a>
<a href="http://easy-trans.fhs-opensource.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/easy_trans.png" msg="Easy-Trans 一个注解搞定数据翻译,减少30%SQL代码量">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/easy_trans.png"
msg="Easy-Trans 一个注解搞定数据翻译,减少30%SQL代码量">
</a>
<a href="https://gitee.com/dromara/neutrino-proxy" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/neutrino-proxy.svg" msg="一款基于 Netty 的、开源的内网穿透神器。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/neutrino-proxy.svg"
msg="一款基于 Netty 的、开源的内网穿透神器。">
</a>
<a href="https://chatgpt.cn.obiscr.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/chatgpt.png" msg="一个支持在 JetBrains 系列 IDE 上运行的 ChatGPT 的插件。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/chatgpt.png"
msg="一个支持在 JetBrains 系列 IDE 上运行的 ChatGPT 的插件。">
</a>
<a href="https://gitee.com/dromara/zyplayer-doc" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/zyplayer-doc.png" msg="zyplayer-doc是一款适合团队和个人使用的WIKI文档管理工具,同时还包含数据库文档、Api接口文档。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/zyplayer-doc.png"
msg="zyplayer-doc是一款适合团队和个人使用的WIKI文档管理工具,同时还包含数据库文档、Api接口文档。">
</a>
<a href="https://gitee.com/dromara/payment-spring-boot" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/payment-spring-boot.png" msg="最全最好用的微信支付V3 Spring Boot 组件。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/payment-spring-boot.png"
msg="最全最好用的微信支付V3 Spring Boot 组件。">
</a>
<a href="https://www.j2eefast.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/j2eefast.png" msg="J2eeFAST 是一个致力于中小企业 Java EE 企业级快速开发平台,我们永久开源!">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/j2eefast.png"
msg="J2eeFAST 是一个致力于中小企业 Java EE 企业级快速开发平台,我们永久开源!">
</a>
<a href="https://gitee.com/dromara/data-compare" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dataCompare.png" msg="数据库比对工具:hive 表数据比对,mysql、Doris 数据比对,实现自动化配置进行数据比对,避免频繁写sql 进行处理,低代码(Low-Code) 平台">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dataCompare.png"
msg="数据库比对工具:hive 表数据比对,mysql、Doris 数据比对,实现自动化配置进行数据比对,避免频繁写sql 进行处理,低代码(Low-Code) 平台">
</a>
<a href="https://gitee.com/dromara/open-giteye-api" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/open-giteye-api.svg" msg="giteye.net 是专为开源作者设计的数据图表服务工具类站点,提供了包括 Star 趋势图、贡献者列表、Gitee指数等数据图表服务。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/open-giteye-api.svg"
msg="giteye.net 是专为开源作者设计的数据图表服务工具类站点,提供了包括 Star 趋势图、贡献者列表、Gitee指数等数据图表服务。">
</a>
<a href="https://gitee.com/dromara/RuoYi-Vue-Plus" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/RuoYi-Vue-Plus.png" msg="后台管理系统 重写 RuoYi-Vue 所有功能 集成 Sa-Token + Mybatis-Plus + Jackson + Xxl-Job + SpringDoc + Hutool + OSS 定期同步">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/RuoYi-Vue-Plus.png"
msg="后台管理系统 重写 RuoYi-Vue 所有功能 集成 Sa-Token + Mybatis-Plus + Jackson + Xxl-Job + SpringDoc + Hutool + OSS 定期同步">
</a>
<a href="https://gitee.com/dromara/RuoYi-Cloud-Plus" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/RuoYi-Cloud-Plus.png" msg="微服务管理系统 重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba Dubbo3.0 Sa-Token Mybatis-Plus MQ OSS ES Xxl-Job Docker 全方位升级 定期同步">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/RuoYi-Cloud-Plus.png"
msg="微服务管理系统 重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba Dubbo3.0 Sa-Token Mybatis-Plus MQ OSS ES Xxl-Job Docker 全方位升级 定期同步">
</a>
<a href="https://gitee.com/dromara/stream-query" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/stream-query.png" msg="允许完全摆脱 Mapper 的 mybatis-plus 体验!封装 stream 和 lambda 操作进行数据返回处理。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/stream-query.png"
msg="允许完全摆脱 Mapper 的 mybatis-plus 体验!封装 stream 和 lambda 操作进行数据返回处理。">
</a>
<a href="https://wind.kim/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sms4j.png" msg="短信聚合工具,让发送短信变的更简单。">
</a>
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sms4j.png"
msg="短信聚合工具,让发送短信变的更简单。">
</a>
<a href="https://cloudeon.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/cloudeon.png" msg="简化kubernetes上大数据集群的运维管理">
</a>
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/cloudeon.png"
msg="简化kubernetes上大数据集群的运维管理">
</a>
<a href="https://github.com/dromara/hodor" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hodor.png"
msg="Hodor是一个专注于任务编排和高可用性的分布式任务调度系统。">
</a>
<a href="http://nsrule.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/test-hub.png"
msg="流程编排,插件驱动,测试无限可能">
</a>
<a href="https://gitee.com/dromara/disjob" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/disjob-2.png"
msg="Disjob是一个分布式的任务调度框架">
</a>
<a href="https://gitee.com/dromara/binlog4j" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/Binlog4j.png"
msg="轻量级 Mysql Binlog 客户端, 提供宕机续读, 高可用集群等特性">
</a>
<a href="https://gitee.com/dromara/yft-design" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/yft-design.png"
msg="基于 Canvas 的开源版 创客贴 支持导出jsonsvg, image文件。">
</a>
<a href="https://gitee.com/dromara/spring-file-storage" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/file4j.png"
msg="在 SpringBoot 中通过简单的方式将文件存储到 本地、阿里云 OSS、腾讯云 COS、七牛云 Kodo等">
</a>
<a href="https://dromara.org/zh/projects/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dromara.png" msg="让每一位开源爱好者,体会到开源的快乐。">
</a>
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dromara.png"
msg="让每一位开源爱好者,体会到开源的快乐。">
</a>
</div>
<div style="height: 10px; clear: both;"></div>
<p>
@@ -508,12 +651,13 @@
</p>
<div style=" margin: 40px 14px 0; padding: 20px 0 10px; background-color: #f4f5f7;">
<h3 style="padding: 0px 0 10px; ">Dromara 知识星球</h3>
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/dromara-xingqiu--sa-token.jpg" style="width: 300px;">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/dromara-xingqiu--sa-token.jpg"
style="width: 300px;">
</div>
</div>
<div style="height: 30px;"></div>
</div>
<!-- ------------ 友情链接 ------------- -->
<div>
<div class="com-box-f s-width">
@@ -522,42 +666,57 @@
<h2 class="s-title">友情链接</h2>
<div class="com-box com-box-you">
<a href="https://okhttps.ejlchina.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/okhttps.png" msg="如艺术一般优雅,像 1、2、3 一样简单,前后端通用,轻量却强大的 HTTP 客户端(同时支持 WebSocket 以及 Stomp 协议)">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/okhttps.png"
msg="如艺术一般优雅,像 1、2、3 一样简单,前后端通用,轻量却强大的 HTTP 客户端(同时支持 WebSocket 以及 Stomp 协议)">
</a>
<a href="https://searcher.ejlchina.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/bean-searcher.png" msg="轻量级关系数据库条件检索引擎,使一行代码实现复杂列表检索成为可能!">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/bean-searcher.png"
msg="轻量级关系数据库条件检索引擎,使一行代码实现复杂列表检索成为可能!">
</a>
<a href="https://xiaonuo.vip/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/xiaonuo2.png" msg="通用型后台权限管理框架,紧随潮流、开箱即用, 同时拥有Vue、Layui、SpringCloud三个版本">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/xiaonuo2.png"
msg="通用型后台权限管理框架,紧随潮流、开箱即用, 同时拥有Vue、Layui、SpringCloud三个版本">
</a>
<a href="http://www.pearadmin.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/pear-admin.png" msg="致 力 于 让 Web 开 发 变 得 简 单 优 雅">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/pear-admin.png"
msg="致 力 于 让 Web 开 发 变 得 简 单 优 雅">
</a>
<a href="http://www.layui-vue.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/layui-vue.png" msg="layui - vue(谐音:类 UI) 是 一 套 Vue 3.0 的 桌 面 端 组 件 库.">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/layui-vue.png"
msg="layui - vue(谐音:类 UI) 是 一 套 Vue 3.0 的 桌 面 端 组 件 库.">
</a>
<a href="https://shenyu.apache.org/zh/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/shenyu.svg" msg="一个异步的,高性能的,跨语言的,响应式的 API 网关。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/shenyu.svg"
msg="一个异步的,高性能的,跨语言的,响应式的 API 网关。">
</a>
<a href="https://dwz.cn/L9hCwepg" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/com/yungouos.png" msg="官方直连支付系统解决方案,支持个人、个体户、企业全渠道签约。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/com/yungouos.png"
msg="官方直连支付系统解决方案,支持个人、个体户、企业全渠道签约。">
</a>
<a href="https://hippo4j.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hippo4j.jpg" msg="强大的动态线程池框架,附带监控报警功能,支持 Tomcat、Jetty、Undertow、RocketMQ、Dubbo、RabbitMQ、Hystrix 消费线程池">
</a>
<a href="http://solon.noear.org/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/solon.png" msg="一个更现代感的应用开发框架:更快、更小、更自由。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hippo4j.jpg"
msg="强大的动态线程池框架,附带监控报警功能,支持 Tomcat、Jetty、Undertow、RocketMQ、Dubbo、RabbitMQ、Hystrix 消费线程池">
</a>
<a href="https://gitee.com/gz-yami/mall4j" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mall4j.png" msg="一个基于Spring Boot 3 JDK17的商城系统。">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mall4j.png"
msg="一个基于Spring Boot 3 JDK17的商城系统。">
</a>
<a href="http://solon.noear.org/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/solon.png"
msg="一个更现代感的应用开发框架:更快、更小、更自由。">
</a>
<a href="https://baomidou.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mybatis-plus.png"
style="max-width: 110%;"
msg="MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。">
</a>
</div>
<div style="height: 10px; clear: both;"></div>
</div>
<div style="height: 60px;"></div>
</div>
<!-- ------------ 底部 连接 ------------- -->
<div id="footer">
<div id="s-footer" class="mao-link"></div>
@@ -566,7 +725,8 @@
<h3>特别鸣谢</h3>
<ul class="list-unstyle">
<li><a href="https://dromara.org/zh/projects/" target="_blank">Dromara社区</a></li>
<li><a href="https://gitee.com/Apache-ShenYu/incubator-shenyu" target="_blank">ShenYu 网关</a></li>
<li><a href="https://gitee.com/Apache-ShenYu/incubator-shenyu" target="_blank">ShenYu 网关</a>
</li>
<li><a href="https://gitee.com/dromara/TLog" target="_blank">TLog 分布式日志</a></li>
</ul>
</div>
@@ -597,30 +757,35 @@
<div class="ss-box">
<h3 class="last" style="text-align: left; float: none; padding-left: 0px;">Sa-Token 公众号</h3>
<div class="media-img padding-small-top" style="text-align: left;">
<img class="dro-qr" src="https://oss.dev33.cn/sa-token/lykj-gzh.jpg" width="100" height="100" />
<img class="dro-qr" src="https://oss.dev33.cn/sa-token/lykj-gzh.jpg" width="100"
height="100" />
</div>
</div>
</div>
</div>
<!-- -------------- 底部 版权 -------------- -->
<div>
<meta charset="UTF-8">
<style type="text/css">
</style>
<div class="foot-box" id="foot">
<div class="s-width" style="text-align: center;">
Copyright ©2022 Sa-Token java权限认证 | sa-token.cc | <a href="https://beian.miit.gov.cn/" target="_blank">鲁ICP备18046274号-4</a>
Copyright ©2022 Sa-Token java权限认证 | sa-token.cc | <a href="https://beian.miit.gov.cn/"
target="_blank">鲁ICP备18046274号-4</a>
</div>
</div>
</div>
</div>
<!-- UI逐渐显现 -->
<style type="text/css">
body{opacity: 0.01; transition: opacity 0.5s;}
body {
opacity: 0.01;
transition: opacity 0.5s;
}
</style>
<script type="text/javascript">
setTimeout(function() {
@@ -642,44 +807,43 @@
s.parentNode.insertBefore(bp, s);
})();
</script>
<!-- 友盟统计 -->
<div style="height: 0px; overflow: hidden;">
<script type="text/javascript" src="https://s4.cnzz.com/z_stat.php?id=1279646043&web_id=1279646043"></script>
</div>
<!-- 百度统计 -->
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?35ad501304eae758ac6139a22a9830f5";
var s = document.getElementsByTagName("script")[0];
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<!-- 悬浮效果 -->
<script src="static/jquery.min.js"></script>
<script src="static/layer-v3.1.1/layer.js"></script>
<script type="text/javascript">
// 鼠标悬浮在友情链接时,提示信息
$(".com-box-you a img").hover(function(){
var msg = $(this).attr("msg") ;
if(msg) {
window.msgLayer = layer.tips(msg, $(this), {tips: 1, time: 0});
$(".com-box-you a img").hover(function() {
var msg = $(this).attr("msg");
if (msg) {
window.msgLayer = layer.tips(msg, $(this), {
tips: 1,
time: 0
});
}
},function(){
}, function() {
var index = window.msgLayer;
setTimeout(function() {
layer.close(index);
}, 1000);
});
// 点击二维码放大
$('.wx-qr,.dro-qr').click(function() {
$('.wx-qr,.dro-qr,.gzh-qr').click(function() {
var w = '300px';
var h = 'auto';
var content = '<div style="height: 100%; overflow: hidden !important;">' +
'<img src="' + this.src + ' " style="width: 100%; height: 100%;" />' +
'</div>';
var content = '<div style="height: 100%; overflow: hidden !important;">' +
'<img src="' + this.src + ' " style="width: 100%; height: 100%;" />' +
'</div>';
layer.open({
type: 1,
title: false,
@@ -689,12 +853,14 @@
content: content
});
})
</script>
<!-- 初始化轮播图 -->
<script src="static/swiper/swiper-bundle.min.js"></script>
<script src="static/swiper/index-swiper.js"></script>
<!-- 修改背景颜色 -->
<script>
// 绑定修改背景色的按钮事件
$('.theme-box span').click(function() {
let bgColor = this.style.backgroundColor;
@@ -703,84 +869,83 @@
})
// 读取上次记录
let bgColor = localStorage.getItem('bg-color-value');
if(bgColor) {
if (bgColor) {
setBg(bgColor);
}
// 设置背景颜色
function setBg(bgColor) {
console.log('---- 背景颜色设定为:', bgColor);
// -------- 设置 body 背景
document.body.style.backgroundColor = bgColor;
// -------- 设置 header 头背景
// 如果是 16 进制,转 rgba
if(bgColor.indexOf('#') == 0) {
if (bgColor.indexOf('#') == 0) {
bgColor = hexToRgba(bgColor, 0.97);
}
// 如果是 rgb,转 rgba
else if(bgColor.match(/\,/g).length == 2) {
else if (bgColor.match(/\,/g).length == 2) {
bgColor = bgColor.replace(')', ' ,0.97)');
}
document.querySelector('.doc-header').style.backgroundColor = bgColor;
}
// 16进制 转 rgba
function hexToRgba(str, a){
function hexToRgba(str, a) {
a = a || 1;
var reg = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/
if(!reg.test(str)){return;}
let newStr = (str.toLowerCase()).replace(/\#/g,'')
if (!reg.test(str)) {
return;
}
let newStr = (str.toLowerCase()).replace(/\#/g, '')
let len = newStr.length;
if(len == 3){
if (len == 3) {
let t = ''
for(var i=0;i<len;i++){
t += newStr.slice(i,i+1).concat(newStr.slice(i,i+1))
for (var i = 0; i < len; i++) {
t += newStr.slice(i, i + 1).concat(newStr.slice(i, i + 1))
}
newStr = t
}
let arr = []; //将字符串分隔,两个两个的分隔
for(var i =0;i<6;i=i+2){
let s = newStr.slice(i,i+2)
for (var i = 0; i < 6; i = i + 2) {
let s = newStr.slice(i, i + 2)
arr.push(parseInt("0x" + s))
}
return 'rgb(' + arr.join(",") + ', ' + a + ')';
return 'rgb(' + arr.join(",") + ', ' + a + ')';
}
</script>
<!-- 图片懒加载 -->
<script src="static/jquery.lazyload-1.9.3.js"></script>
<script>
$(function() {
$("img.lazy").lazyload({
effect: "fadeIn", // 动画,show=显示,fadeIn=淡入,slideDown=下拉
effectspeed: 1200, // 动画持续时间
effect: "fadeIn", // 动画,show=显示,fadeIn=淡入,slideDown=下拉
effectspeed: 1200, // 动画持续时间
skip_invisible: true, // 不加载隐藏的图像
// threshold: -180, // 提前加载:距离屏幕多少px时就显示出来
// event: 'click', // 事件触发时才加载,scroll=滑动,click=点击,mouseover=鼠标划过,sporty=运动的
// 未加载时的占位图,此为3x3透明小图片
placeholder:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAhdEVYdENyZWF0aW9uIFRpbWUAMjAyMTowMToyMiAyMjoxNDoxM63SwyUAAAANSURBVBhXYyAGMDAAAAAnAAF2ypRxAAAAAElFTkSuQmCC",
load: function(){
placeholder: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAhdEVYdENyZWF0aW9uIFRpbWUAMjAyMTowMToyMiAyMjoxNDoxM63SwyUAAAANSURBVBhXYyAGMDAAAAAnAAF2ypRxAAAAAElFTkSuQmCC",
load: function() {
console.log('lazy img: ' + this.src);
}
});
})
// $(window).bind("load", function() {
// // var timeout = setTimeout(function() {$("img.lazy").trigger("sporty")}, 5000);
// });
</script>
<!-- 预览版提示 -->
<script type="text/javascript">
// 预览版提示
if(location.host === 'rc.sa-token.cc') {
const newTips = '<b>当前文档为RC预览版文档,仅做学习测试使用,正式项目请使用正式版:<a href="https://sa-token.cc/" target="_blank">https://sa-token.cc/</a></b>';
if (location.host === 'rc.sa-token.cc') {
const newTips =
'<b>当前文档为RC预览版文档,仅做学习测试使用,正式项目请使用正式版:<a href="https://sa-token.cc/" target="_blank">https://sa-token.cc/</a></b>';
layer.alert(newTips);
}
</script>
</body>
</html>
</html>
+2
View File
@@ -16,6 +16,7 @@
<!---------------------------- tabs:start ------------------------------>
<!-------- tab:Maven 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-reactor-spring-boot-starter` 修改为 `sa-token-reactor-spring-boot3-starter` 即可。
``` xml
<!-- Sa-Token 权限认证(Reactor响应式集成), 在线文档:https://sa-token.cc -->
<dependency>
@@ -36,6 +37,7 @@
</dependency>
```
<!-------- tab:Gradle 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-reactor-spring-boot-starter` 修改为 `sa-token-reactor-spring-boot3-starter` 即可。
``` gradle
// Sa-Token 权限认证(Reactor响应式集成),在线文档:https://sa-token.cc
implementation 'cn.dev33:sa-token-reactor-spring-boot-starter:${sa.top.version}'
+5 -1
View File
@@ -11,6 +11,7 @@
<!---------------------------- tabs:start ---------------------------->
<!-------- tab:Maven 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-spring-boot-starter` 修改为 `sa-token-spring-boot3-starter` 即可。
``` xml
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency>
@@ -20,6 +21,7 @@
</dependency>
```
<!-------- tab:Gradle 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-spring-boot-starter` 修改为 `sa-token-spring-boot3-starter` 即可。
``` gradle
// Sa-Token 权限认证,在线文档:https://sa-token.cc
implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}'
@@ -28,6 +30,7 @@ implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}'
<!---------------------------- tabs:start ------------------------------>
<!-------- tab:Maven 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-reactor-spring-boot-starter` 修改为 `sa-token-reactor-spring-boot3-starter` 即可。
``` xml
<!-- Sa-Token 权限认证(Reactor响应式集成),在线文档:https://sa-token.cc -->
<dependency>
@@ -37,6 +40,7 @@ implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}'
</dependency>
```
<!-------- tab:Gradle 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-reactor-spring-boot-starter` 修改为 `sa-token-reactor-spring-boot3-starter` 即可。
``` gradle
// Sa-Token 权限认证(Reactor响应式集成),在线文档:https://sa-token.cc
implementation 'cn.dev33:sa-token-reactor-spring-boot-starter:${sa.top.version}'
@@ -50,7 +54,7 @@ implementation 'cn.dev33:sa-token-reactor-spring-boot-starter:${sa.top.version}'
因为这个SpringMVC是基于Servlet模型的,在这里我们需要引入的是`sa-token-spring-boot-starter`
对于网关服务,大体来讲分为两种:
- 一种是基于Servlet模型的,如:Zuul,我们需要引入的是:`sa-token-spring-boot-starter`,详细戳:[在SpringBoot环境集成](/start/example)
- 一种是基于Servlet模型的,如:Zuul,我们需要引入的是:`sa-token-spring-boot-starter`,详细戳:[在SpringBoot环境集成](/start/example);理论上`Zuul`并不支持`Spring Boot3`
- 一种是基于Reactor模型的,如:SpringCloud Gateway、ShenYu 等等,我们需要引入的是:`sa-token-reactor-spring-boot-starter`,**并且注册全局过滤器!**,详细戳:[在WebFlux环境集成](/start/webflux-example)
注:切不可直接在一个项目里同时引入这两个依赖,否则会造成项目无法启动
+10 -3
View File
@@ -10,7 +10,7 @@
1. 物理隔离:子服务部署在指定的内网环境中,只有网关对外网开放
2. 逻辑隔离:子服务与网关同时暴露在外网,但是子服务会有一个权限拦截层保证只接受网关发送来的请求,绕过网关直接访问子服务会被提示:无效请求
这种鉴权需求牵扯到两个环节:**`网关转发鉴权`**、**`服务内部调用鉴权`**
这种鉴权需求牵扯到两个环节: **`网关转发鉴权`****`服务内部调用鉴权`**
Sa-Token提供两种解决方案:
1. 使用 OAuth2.0 模式的凭证式,将 Client-Token 用作各个服务的身份凭证进行权限校验
@@ -25,6 +25,7 @@ Sa-Token提供两种解决方案:
在网关处引入的依赖为(此处以 SpringCloud Gateway 为例):
<!---------------------------- tabs:start ------------------------------>
<!-------- tab:Maven 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-reactor-spring-boot-starter` 修改为 `sa-token-reactor-spring-boot3-starter` 即可。
``` xml
<!-- Sa-Token 权限认证(Reactor响应式集成), 在线文档:https://sa-token.cc -->
<dependency>
@@ -45,6 +46,7 @@ Sa-Token提供两种解决方案:
</dependency>
```
<!-------- tab:Gradle 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-reactor-spring-boot-starter` 修改为 `sa-token-reactor-spring-boot3-starter` 即可。
``` gradle
// Sa-Token 权限认证(Reactor响应式集成),在线文档:https://sa-token.cc
implementation 'cn.dev33:sa-token-reactor-spring-boot-starter:${sa.top.version}'
@@ -55,9 +57,10 @@ implementation 'org.apache.commons:commons-pool2'
```
<!---------------------------- tabs:end ------------------------------>
在子服务引入的依赖为:
下游子服务引入的依赖为:
<!---------------------------- tabs:start ------------------------------>
<!-------- tab:Maven 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-spring-boot-starter` 修改为 `sa-token-spring-boot3-starter` 即可。
``` xml
<!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc -->
<dependency>
@@ -78,6 +81,7 @@ implementation 'org.apache.commons:commons-pool2'
</dependency>
```
<!-------- tab:Gradle 方式 -------->
注:如果你使用的是 `SpringBoot 3.x`,只需要将 `sa-token-spring-boot-starter` 修改为 `sa-token-spring-boot3-starter` 即可。
``` gradle
// Sa-Token 权限认证,在线文档:https://sa-token.cc
implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}'
@@ -146,7 +150,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
> 如果通过网关转发,可以正常访问,直接访问子服务会提示:`无效Same-Tokenxxx`
### 三、服务内部调用鉴权
### 三、服务内部调用鉴权
有时候我们需要在一个服务调用另一个服务的接口,这也是需要添加`Same-Token`作为身份凭证的
@@ -163,6 +167,9 @@ public class FeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken());
// 如果希望被调用方有会话状态,此处就还需要将 satoken 添加到请求头中
// requestTemplate.header(StpUtil.getTokenName(), StpUtil.getTokenValue());
}
}
```
+2
View File
@@ -5,6 +5,8 @@
---
- [[ CSDN ] 【Sa-Token】9、Sa-Token实现在线用户管理功能](https://blog.csdn.net/qq_40065776/article/details/132180932) 2023-08-09
- [[ CSDN ] 【RuoYi-Vue-Plus】学习笔记 31 - Sa-Token(五)登录验证拦截器之 Token 有效期及其续签(Sa-Token 源码)](https://blog.csdn.net/Michelle_Zhong/article/details/126071871) 2022-07-30
- [[ CSDN ] 【RuoYi-Vue-Plus】学习笔记 29 - Sa-Token(四)V1.30.0 登录流程分析(Sa-Token 源码)](https://blog.csdn.net/Michelle_Zhong/article/details/125659797) 2022-07-07
+66 -1
View File
@@ -58,7 +58,8 @@ Sa-Token 的部分 API 只能在 Web 上下文中才能调用,例如:`StpUti
- 什么?你说你两个都引入了?那你的项目能启动成功吗?
4. 如果是 WebFlux 环境而且正确引入了依赖,依然报错,**请检查是否注册了 SaReactorFilter 全局过滤器,在 WebFlux 下这一步是必须的**,具体还是请参考上面的 [ 在WebFlux环境集成 ] 章节。
5. 需要仔细注意,如果你使用的是 Springboot3.x 版本,就不要错误的引入 `sa-token-spring-boot-starter`,需要引入的是 `sa-token-spring-boot3-starter`,不然就会导致框架报错。
6. 如果以上步骤排除无误后依然报错,请直接提 issue 或者加入QQ群求助。
6. 如果你的项目开启了全局懒加载(spring.main.lazy-initialization=true)后,能启动项目,但是访问接口报异常,请直接参考:[Q:开启了全局懒加载后,能启动项目,但是访问接口报未能获取有效的上下文处理器](/more/common-questions?id=q:开启了全局懒加载后,能启动项目,但是访问接口报未能获取有效的上下文处理器)
7. 如果以上步骤排除无误后依然报错,请直接提 issue 或者加入QQ群求助。
### Q:报错:NotLoginExceptionxxx
@@ -71,6 +72,7 @@ Sa-Token 的部分 API 只能在 Web 上下文中才能调用,例如:`StpUti
- 可能4:前端提交了 Token,但是 Token前缀 不对,可参考:[自定义 Token 前缀](/up/token-prefix)
- 可能5:你的项目属于前后端分离架构,此时浏览器默认不自动提交 Cookie,参考:[前后端分离](/up/not-cookie)
- 可能6:你使用了 Nginx 反向代理,而且配置了 自定义Token名称,而且自定义的名称还带有下划线(比如 shop_token),而且还是你的项目还是从 Header头提交Token的,此时 Nginx 默认会吞掉你的下划线参数,可参考:[nginx做转发时,带下划线的header参数丢失](https://blog.csdn.net/zfw_666666/article/details/124420828)
- 可能7:可能是跨域了,导致前端提交不上 token,看看前端浏览器有没有跨域的报错。
**如果是:Token无效:6ad93254-b286-4ec9-9997-4430b0341ca0**
- 可能1:前端提交的 token 是乱填的,或者从别的项目拷过来的,或者多个项目一起开发时彼此的 Token 串项目了。
@@ -301,6 +303,16 @@ public class SaTokenApplication {
### Q:我把 token 有效期设置为 30 天,但是总感觉不到 30 天的时候 token 就无效了,怎么回事?
- 可能1:你没有为 sa-token 集成 Redis,框架默认将会话数据保存在内存中,项目重启后数据会消失。
- 可能2:你为 sa-token 集成了 Redis,但是 Redis 重启了,导致会话消失。
- 可能3:你配置了 `is-concurrent=false`,不允许同一账号多端登录,有别人登录了这个账号把你顶下去了。
- 可能4:你配置了 `is-concurrent=true`,但是`is-share=false`,同一账号每次登录产生不同的 token,默认最高可以同时登录12个客户端,超过将自动注销最原先的会话。
- 可能5:你的这个账号,别人也登录了,别人调用了注销方法,把你这边的也注销了。`StpUtil.logout()` 为单 token 注销,`StpUtil.logout(10001)` 为账号所有 token 注销。
- 可能6:你虽然 `sa-token.timeout` 配置了 30 天,但是 `sa-token.active-timeout` 配置了较短的值,超过这个时间无操作,token 就过期了。
- 可能7:你换了浏览器,或者换了电脑,或者清空了浏览器最近缓存记录,自然而然需要重新登录。
- 可能8:你中途改了项目配置,比如改了 `sa-token.token-name` 配置项的值,会导致会话保存的 key 发生改变,效果等同于手动清空了 Redis 数据,需要重新登录。
### Q:有时候我不加 Token 也可以通过鉴权,请问是怎么回事?
@@ -438,6 +450,26 @@ spring.mvc.throw-exception-if-no-handler-found=true
### Q:开启了全局懒加载后,能启动项目,但是访问接口报“未能获取有效的上下文处理器”
开启了全局懒加载后,能启动项目,但是访问接口报异常 `InvalidContextException`: 未能获取有效的上下文处理器, 配置如下:
``` yaml
spring:
main:
lazy-initialization: true
```
原因是 Sa-Token 自动配置入口类 SaBeanInject 被延迟加载了,只需要手动指定懒加载排除掉 SaBeanInject 就可以了,实现代码如下:
``` java
@Configuration
class MyConfiguration {
@Bean
LazyInitializationExcludeFilter integrationLazyInitExcludeFilter() {
return LazyInitializationExcludeFilter.forBeanTypes(SaBeanInject.class);
}
}
```
[经验来源](https://gitee.com/dromara/sa-token/issues/I7EXIU)
<!-- ---------------------------- 常见疑问 ----------------------------- -->
@@ -592,6 +624,39 @@ So:从鉴权粒度的角度来看,需要针对一个模块鉴权的时候,
所以只能统一抛出-2,这个行为也和具体使用的 SaTokenDao 有关联,例如集成 sa-token-jwt 插件后,框架就能分辨出来是 token 过期了,抛出-3。
### QSa-Token 是否提供类似 RefreshToken 的概念,与 AccessToken 相互配合刷新令牌鉴权。
关于长短 tokenSa-Token 没有提供直接的 API 支持,但是你可以利用 “临时 token 认证模块” 轻易的达到这一点:
1. 把 `sa-token.timeout` 的值配置小一点,然后把 `StpUtil.login(10001)` 生成的 token 作为短 token ,用来鉴权。
2. 用 “临时 token 认证模块” 生成长 token `String refreshToken = SaTempUtil.createToken(10001, 2592000);`。
3. 把这两个 token 一起返回到前端。
4. 你再开个接口,可以让前端通过长 token,刷新短 token,参考代码:
``` java
@RequestMapping("/refreshToken")
public SaResult refreshToken(String refreshToken) {
// 1、验证
Object userId = SaTempUtil.parseToken(refreshToken);
if(userId == null) {
return SaResult.error("无效 refreshToken");
}
// 2、为其生成新的短 token
String accessToken = StpUtil.createLoginSession(userId);
// 3、返回
return SaResult.data(accessToken);
}
```
### Q:怎么改变请求返回的 http 状态码?
``` java
SaHolder.getResponse().setStatus(401)
```
### Q:还是有不明白到的地方?
请在`gitee` 、 `github` 提交 `issues`,或者加入qq群交流,[群链接](/more/join-group)
+3 -3
View File
@@ -1,14 +1,14 @@
# 加入讨论群
加入 Sa-Token 专属讨论群,与众多大佬一起努力 (huá shǔi) 成长 (mō yú)。
加入 Sa-Token 专属讨论群,与众多大佬一起努力 (huá sh) 成长 (mō yú)。
---
### 1、加入QQ交流群
![QQ群](https://oss.dev33.cn/sa-token/qq-group-4.png ':size=180')
![QQ群](https://oss.dev33.cn/sa-token/qr/qq-group-5-gsa.png ':size=180')
QQ交流群:707350988 [点击加入](https://jq.qq.com/?_wv=1027&k=tqbzHT2D)
QQ交流群:837325627 [点击加入](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=98NOhX0Q3a2hcv3eURcnYMBuZUZrlHUH&authKey=td3pmX3BnYNr%2FCRkEDwE5FgGARk29D9HAMwL0bAfK7tqN8XN93jccnEanyZl18mM&noverify=0&group_code=837325627)
### 2、加入微信交流群:
+34 -11
View File
@@ -1,13 +1,15 @@
# 使用 Sa-Token 的开源项目
> 集成 Sa-Token 的开源案例收集,取自 [Awesome-Sa-Token](https://gitee.com/sa-token/awesome-sa-token),定期同步。
> 集成 Sa-Token 的开源案例收集,取自 [Awesome-Sa-Token](https://gitee.com/sa-tokens/awesome-sa-token),定期同步。
---
### 后台管理
- [[ srppms ]](https://gitee.com/cai-bin00/srppms):基于SpringBoot+Vue+sa-token前后端分离的科研项目管理平台。
- [[ twelvet-fast ]](https://gitee.com/twelvet/twelvet-fast):基于Spring Boot 3 JDK17的单体服务极速开发管理平台脚手架,先行体验最新技术栈。
- [[ Sa-Plus ]](https://gitee.com/click33/sa-plus):一个基于 SpringBoot 架构的快速开发框架,内置代码生成器。
@@ -58,6 +60,12 @@
- [[ springboot-multi-tenant-sa-token ]](https://gitee.com/willf/springboot-multi-tenant-sa-token):轻量的多租户权限管理系统脚手架(SpringBootSa-Tokenmybatis-plusVue & Element)。
- [[ solon_angis_beetlsql ]](https://gitee.com/smartcity/solon_angis_beetlsql):并元国产开发平台 solon、sa-token、beetlsql、smart-http
- [[ zeta-kotlin ]](https://gitee.com/xia5800/zeta-kotlin)zeta-kotlin是使用kotlin语言基于spring boot、mybatis-plus、sa-token等框架开发的项目脚手架。
- [[ nebula-swagger-demo ]](https://gitee.com/flgitee/nebula-swagger-demo)springboot+nebula 集成knife4j案例
### 微服务相关
@@ -69,8 +77,6 @@
- [[ falser-cloud ]](https://gitee.com/falser/falser-cloud): 基于 SpringCloud Alibaba + SpringCloud gateway + SpringBoot + Sa-Token + vue-admin-template + Nacos + Rabbit MQ + Redis 的一个后台管理系统,前后端分离,权限管理,菜单管理,数据字典,停车场系统管理等功能
- [[ Huanxing-mall ]](https://gitee.com/lijiaxing_boy/huanxing-mall)HuanXing 商城基于SpringCloud 2021 & Alibaba + Sa-token,前端基于 Vue3 +Element plus 的微服务商城
- [[ dcy-fast-cloud ]](https://gitee.com/dcy421/dcy-fast-cloud):一个基于 SpringCloudAlibaba + Sa-Token + dubbo2.7.8 + Seata + knife4j + Mybatis-Plus + MapStruct + 的后台管理系统,前端vue-element-admin,并且内置代码生成器+动态路由权限等功能
- [[ fhs-framework ]](https://gitee.com/fhs-opensource/fhs-framework):基于Springboot+Springcloud + Mybatis Plus + Sa-Token + Vue + ElementUI 的快速开发平台(低代码开发平台),本框架永远免费,永久全开源
@@ -81,6 +87,30 @@
- [[ BudWk-V7 ]](https://gitee.com/budwk/budwk):基于 NutzBoot + Sa-Token + Dubbo + Nacos注册&配置中心 的微服务开发脚手架(同时提供单应用版本),带有配套后台管理前端模板及代码生成器
- [[ xr-satoken-cloud ]](https://gitee.com/fzhxfw/xr-satoken-cloud):一款基于SaToken轻量级Java权限认证框架构建的微服务后台开发脚手架,基于SpringCloud + SpringCloudAlibaba + Nacos + SaToken + Mybatis等技术搭建,内置RBAC权限管理,代码生成器,文件分片速传等,本项目完全开源免费,定期提交代码到dev开发分支,由个人开发者业余时间维护升级。
- [[ CloudEon ]](https://gitee.com/dromara/CloudEon):一款基于kubernetes的开源大数据平台,旨在为用户提供一种简单、高效、可扩展的大数据解决方案。
- [[ quick-boot ]](https://github.com/csx-bill/quick-boot):一款基于 Spring Cloud 2022 、Spring Boot 3、AMIS 和 APIJSON 的低代码系统。
### 商城
- [[ litemall-plus ]](https://gitee.com/ysling-org/litemall-plus):微信小程序SaaS商城系统,可支持多小程序同时运行。
- [[ mall4j ]](https://gitee.com/gz-yami/mall4j):基于Spring Boot 3 JDK17的一个商城手脚架。
- [[ Huanxing-mall ]](https://gitee.com/lijiaxing_boy/huanxing-mall)HuanXing 商城基于SpringCloud 2021 & Alibaba + Sa-token,前端基于 Vue3 +Element plus 的微服务商城
### 博客
- [[ jthink ]](https://gitee.com/wtsoftware/jthink) 一个基于 SpringBoot + Sa-Token + Thymeleaf 的博客系统
- [[ 拾壹博客 ]](https://gitee.com/quequnlong/shiyi-blog):一款vue+springboot前后端分离的博客系统,博客后台管理系统使用了vue+elmentui开发,后端使用Sa-Token进行权限管理,支持动态菜单权限,动态定时任务,文件支持本地和七牛云上传,使用ElasticSearch作为全文检索服务,支持QQ、微博、码云登录。
- [[ June 12 ]](https://gitee.com/hanshaung/ants)June 12 是一个纯开源免费的资讯/博客类网站,基于Spring Boot + Sa-Token + Vue开发。
### 插件
@@ -93,17 +123,10 @@
### 其它
- [[ jthink ]](https://gitee.com/wtsoftware/jthink) 一个基于 SpringBoot + Sa-Token + Thymeleaf 的博客系统
- [[ Sa-Token-Study ]](https://gitee.com/click33/sa-token-study):以demo示例的方式讲解 Sa-Token 源码涉及到的技术点,连载中……
- [[ Sa-Token-Study ]](https://gitee.com/sa-tokens/sa-token-study):以demo示例的方式讲解 Sa-Token 源码涉及到的技术点,连载中……
- [[ SpringMvc+Sa-Token ]](https://gitee.com/SRD_01/spring-mvc-sa-token): Jsp+SpringMVC+SSO+Sa-Token+Redis | Spring MVC 集成 SaToken Demo 项目
- [[ iot-kit ]](https://gitee.com/iotkit-open-source/iotkit-parent):一个轻量级低门槛的物联网平台,包含了多协议设备接入、规则引擎、第三方平台接入、智能家居小程序等模块的项目,基于SpringBoot架构并集成了Sa-Token的OAuth2认证。
- [[ 拾壹博客 ]](https://gitee.com/quequnlong/shiyi-blog):一款vue+springboot前后端分离的博客系统,博客后台管理系统使用了vue+elmentui开发,后端使用Sa-Token进行权限管理,支持动态菜单权限,动态定时任务,文件支持本地和七牛云上传,使用ElasticSearch作为全文检索服务,支持QQ、微博、码云登录。
- [[ cubic ]](https://gitee.com/dromara/cubic):一站式问题定位平台,实时线程栈监控、线程池监控、动态arthas命令集、依赖分析等等等,助你快速定位问题。
+17 -3
View File
@@ -21,6 +21,18 @@ Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永
| 赞助人 | 赞助金额 | 留言 | 时间 |
| :-------- | :-------- | :-------- | :-------- |
| [Meteor](https://gitee.com/meteoroc) | ¥ 2.5 | 感谢您的开源项目! | 2023-08-23 |
| [刘斌](https://gitee.com/xuanfather) | ¥ 20.0 | 感谢您的开源项目! | 2023-08-17 |
| [快快乐乐小码农](https://gitee.com/happy-little-farmer) | ¥ 1.0 | 感谢您的开源项目! | 2023-08-17 |
| [失败女神](https://gitee.com/failedgoddess) | ¥ 50.0 | 感谢您的开源项目! | 2023-08-03 |
| 结弦奏(微信打赏) | ¥ 50.0 | 感谢您的开源项目! | 2023-08-07 |
| [好心肠的老哥](https://gitee.com/ntdm) | ¥ 10.0 | 非常好的开源项目,希望越来越好! | 2023-08-02 |
| [XiaoYi](https://gitee.com/getianit) | ¥ 100.0 | [亚洲云深圳BGP云服务器](https://www.asiayun.com/cart?action=configureproduct&pid=300) | 2023-07-24 |
| [张兆伟](https://gitee.com/zhang865700) | ¥ 50.0 | 感谢您的开源项目! | 2023-07-24 |
| [mikeinshanghai](https://gitee.com/mikeinshanghai)| ¥ 50.0 | Sa-Token, MeterSphere共成长,共辉煌! | 2023-07-14 |
| 吴其敏(微信打赏) | ¥ 200.0 | [CAT 是基于 Java 开发的实时应用监控平台,为美团点评提供了全面的实时监控告警服务。](https://github.com/dianping/cat) | 2023-07-11 |
| [Dear胜哥](https://gitee.com/DearShengGe) | ¥ 10.0 | 有幸在摸鱼时间认真看完了全文档,感觉很是不错。开源不易,望作者继续扩展该框架功能! | 2023-06-30 |
| [SP](https://gitee.com/LSP1999) | ¥ 10.0 | 就是需要这种简单上手的项目 | 2023-06-15 |
| [javahuang](https://gitee.com/javahrp) | ¥ 200.0 | [SurveyKing:功能最强大的调查问卷系统和考试系统,开源](https://gitee.com/surveyking/surveyking) | 2023-06-08 |
| [dyjgitdyjgit](https://gitee.com/qtinfogit) | ¥ 20.0 | 感谢您的开源项目! | 2023-05-22 |
| 砰嚓嚓(QQ打赏) | ¥ 20.0 | 一点打赏不成敬意 | 2023-05-15 |
@@ -142,9 +154,11 @@ Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永
### 商业赞助
一次性赞助 100 元或以上,可帮助您的产品在 Sa-Token 交流群艾特全体成员推广一次。
一次性赞助 200 元或以上,可帮助您的产品在 Sa-Token 交流群艾特全体成员推广一次。
Sa-Token 目前总计10+微信交流群(每个群人数400以上,总人数5000+),4个QQ交流群(2000人群和1000人群,总计人数6000+),大部分为 java 开发工程师,可有效推广您的产品
并同时在赞助列表处高亮产品链接
Sa-Token 目前总计14+微信交流群(每个群人数大约400以上,总计人数5000+),4个QQ交流群(2000人群和1000人群,总计人数6000+),大部分为 java 开发工程师,可有效推广您的产品。
- 优先推广和程序员相关的互联网产品,比如:低代码开发平台、网课、开发软件、云服务器、个人博客等等,实体产品如键盘、显示器、耳机等等,如果是和程序员无关的产品,可酌情考虑是否推广。
- 拒绝接受违反法律法规、以及灰色相关的产品推广,为避免不必要的麻烦,目前也拒绝推广IP代理、上网工具等等。
@@ -158,7 +172,7 @@ Sa-Token 目前总计10+微信交流群(每个群人数400以上,总人数50
``` txt
感谢 xx 老板对 Sa-Token 的商业赞助,以下是老板的产品,大家感兴趣的可以关注一下:
xxx 商品名称
链接:https://xxx.com/xxx
链接:https://xxxxxn.com/xxx
```
> 目前不接受 Sa-Token 官网文档插入广告推广,只接受一次性商业赞助推广。
+56 -36
View File
@@ -1,7 +1,27 @@
# 更新日志
### v1.36.0 @2023-9-22
- sa-token-core
- 修复:API接口签名校验参数接口NPE问题,增加必须参数的非空校验处理。
- 新增:加密工具类新增 sha384、sha512 实现。 感谢 `@若初995` 提交的pr。 **[重要]**
- 修复:`SaFoxUtil.vagueMatch()` 正则匹配的一些问题。 **[漏洞修复]**
- 修复:`SaRouter.match()` 路由匹配的一些问题。 **[漏洞修复]**
- 其它:
- 优化:`sa-token-alone-redis` 去掉不必要的配置项判断。
- 新增:`sa-token-solon-plugin` 增加对 solon 网关的支持。
- 新增:新增第三方插件专用仓库:`sa-token-three-plugin`
- 升级:`sa-token-solon-plugin` 增加对 solon 网关的支持。
- 文档:
- 新增:新增开启全局懒加载时不能注入上下文处理器的处理方案 。
- 新增:新增 RefreshToken 示例。 **[重要]**
- 新增:文档新增 sa-token 小助手,可在线实时技术提问。 **[重要]**
- 优化:其它一些优化。
- 新增插件:
- `sa-token-redisson-jackson2`:通用 redisson 集成方案 spring, solon, jfinal 等都可用)
### 2023-6-23 @v1.35.0
### v1.35.0 @2023-6-23
- sa-token-core
- 优化:前端未提供 token 时,`getTokenSession()` 将抛出未登录异常,而不是返回 null。 **[不向下兼容]**
- 新增:SaSession 新增字段:`type``loginType``loginId``token`
@@ -69,7 +89,7 @@
- `sa-token-context-grpc` -> `sa-token-grpc`
### 2023-1-11 @v1.34.0
### v1.34.0 @2023-1-11
新增插件:
- 新增:新增 `SpringBoot3.x` 集成插件,感谢 `@jry` 提供的参考思路。 **[重要]**
@@ -95,7 +115,7 @@ sa-token-sso 单点登录:
### 2022-11-16 @v1.33.0
### v1.33.0 @2022-11-16
- 重构:重构异常状态码机制。 **[重要]**
- 重构:重构 sa-token-sso 模块异常码改为 300 开头,sa-token-jwt 异常码改为 302 开头。 **[不向下兼容]**
- 新增:新增全局 Log 模块。 **[重要]**
@@ -106,7 +126,7 @@ sa-token-sso 单点登录:
### 2022-10-28 @v1.32.0
### v1.32.0 @2022-10-28
- 修复:修复 sa-token-dao-redis-fastjson 插件多余序列化 `timeout` 字段的问题。
- 修复:修复 sa-token-dao-redis-fastjson 插件 `session.getModel` 无法反序列化实体类的问题。
- 修复:修复 `sa-token-quick-login` 插件指定拦截排除路由不生效的问题。
@@ -146,7 +166,7 @@ sa-token-sso 单点登录:
### 2022-9-8 @v1.31.0
### v1.31.0 @2022-9-8
- 文档:新增优秀开源案例展示。
- 文档:新增博客展示,欢迎大家投稿。
- 新增:新增 `SaInterceptor` 综合拦截器。 **[重要]** **[不向下兼容]**
@@ -185,7 +205,7 @@ sa-token-sso 单点登录:
### 2022-05-9 @v1.30.0
### v1.30.0 @2022-05-9
- 新增:新增集成 Web-Socket 鉴权示例。 **[重要]**
- 新增:新增集成 Web-Socket(Spring封装版) 鉴权示例。
- 新增:新增 jfinal 集成包 `sa-token-jfinal-plugin` **[重要]**
@@ -230,7 +250,7 @@ sa-token-sso 单点登录:
- 修复:修复 `StpLogicJwtForSimple` 模式下 Extra 数据可能受到旧 token 影响的bug
### 2022-02-10 @v1.29.0
### v1.29.0 @2022-02-10
- 升级:sa-token-jwt插件可在登录时添加额外数据。
- 重构:优化Dubbo调用时向下传递Token的规则,可避免在项目启动时由于Context无效引发的bug。
- 重构:OAuth2 授权模式开放由全局配置和Client单独配置共同设定。
@@ -252,7 +272,7 @@ sa-token-sso 单点登录:
- 完善:完善单元测试。
### 2021-11-5 @v1.28.0
### v1.28.0 @2021-11-5
- 新增:新增 `sa-token-jwt` 插件,用于与jwt的整合 **[重要]**
- 新增:新增 `sa-token-context-dubbo` 插件,用于与 Dubbo 的整合 **[重要]**
- 文档:文档新增章节:Sa-Token 插件开发指南 **[重要]**
@@ -266,7 +286,7 @@ sa-token-sso 单点登录:
- 文档:新增常见问题总结
### 2021-10-11 @v1.27.0
### v1.27.0 @2021-10-11
- 升级:增强 SaRouter 链式匹配能力 **[重要]**
- 新增:新增插件 Thymeleaf 标签方言 **[重要]**
- 新增:@SaCheckPermission 增加 orRole 字段,用于权限角色“双重or”匹配 **[重要]**
@@ -291,7 +311,7 @@ sa-token-sso 单点登录:
- [不向下兼容] 侦听器 doLogoutByLoginId 方法重命名为 doKickout
### 2021-9-2 @v1.26.0
### v1.26.0 @2021-9-2
- 优化:优化单点登录文档
- 新增:新增 `Http Basic` 认证 **[重要]**
- 新增:文档新增跨域解决方案
@@ -300,7 +320,7 @@ sa-token-sso 单点登录:
- 示例:新增 `SSO-Server` 端前后端分离示例 **[重要]**
### 2021-8-16 @v1.25.0
### v1.25.0 @2021-8-16
- 新增:`SaRequest`新增`getHeader(name, defaultValue)`方法,用于获取header默认值
- 新增:`SaRequest` 添加 `forward` 转发方法
- 新增:Readme新增源码模块介绍、友情链接、正在使用Sa-Token的项目
@@ -320,7 +340,7 @@ sa-token-sso 单点登录:
- 重构:修复 `SaReactorHolder.getContent()` 拼写错误:`content` -> `context`
### 2021-7-24 @v1.24.0
### v1.24.0 @2021-7-24
- 修复:修复部分场景下Alone-Redis插件导致项目无法启动的问题
- 优化:增加对SpringBoot1.x版本的兼容性
- 新增:SaOAuth2Util新增checkScope函数,用于校验令牌是否具备指定权限
@@ -330,14 +350,14 @@ sa-token-sso 单点登录:
- 优化:大幅度优化文档示例
### 2021-7-19 @v1.23.0
### v1.23.0 @2021-7-19
- 新增:Sa-Token-OAuth2 模块正式发布 **[重要]**
- 修复:修复jwt集成demo无法正确注册StpLogic的bug
- 修复:修复登录时某些场景下Session续期可能不正常的bug
- 优化:代码注释优化,文档优化
### 2021-7-10 @v1.22.0
### v1.22.0 @2021-7-10
- 新增:SaSsoConfig 部分属性增加set连缀风格
- 优化:SaSsoUtil 可定制化底层的 `StpLogic`
- 新增:新增 `SaSsoHandle` 大幅度简化单点登录整合步骤 **[重要]**
@@ -346,7 +366,7 @@ sa-token-sso 单点登录:
- 优化:大幅度优化文档示例
### 2021-7-2 @v1.21.0
### v1.21.0 @2021-7-2
- 新增:新增Token二级认证 **[重要]**
- 新增:新增`Sa-Token-Alone-Redis`独立Redis插件 **[重要]**
- 新增:新增SSO三种模式,彻底解决所有场景下的单点登录问题 **[重要]**
@@ -356,7 +376,7 @@ sa-token-sso 单点登录:
- 更改yml配置前缀:原`[spring.sa-token.]` 改为 `[sa-token.]`,目前版本暂时向下兼容,请尽快更新
### 2021-6-17 @v1.20.0
### v1.20.0 @2021-6-17
- 新增:新增Solon适配插件,感谢大佬 `@刘西东` 提供的pr **[重要]**
- 新增:新增`SaRouter.stop()`函数,用于一次性跳出匹配链功能 **[重要]**
- 新增:新增单元测试 **[重要]**
@@ -377,7 +397,7 @@ sa-token-sso 单点登录:
- 为保证平滑更新,旧API仍旧保留,但已增加`@Deprecated`注解,请尽快更新至新API
### 2021-5-10 @v1.19.0
### v1.19.0 @2021-5-10
- 新增:注解鉴权新增定制loginType功能 **[重要]**
- 重构:重构目录结构,抽离`plugin`模块 **[重要]**
- 新增:新增 `sa-token-quick-login` 插件,零代码集成登录功能 **[重要]**
@@ -385,7 +405,7 @@ sa-token-sso 单点登录:
- 优化:文档优化...
### 2021-4-24 @v1.18.0
### v1.18.0 @2021-4-24
- 新增:新增权限通配符功能,灵活设置权限 **[重要]**
- 修复:修复自动续签处的逻辑错误
- 新增:新增Web开发常见漏洞防护建议
@@ -398,7 +418,7 @@ sa-token-sso 单点登录:
- 重构:`SaTokenInsideUtil` -> `SaFoxUtil`
### 2021-4-17 @v1.17.0
### v1.17.0 @2021-4-17
- 修复:在WebFlux环境中引入Redis集成包无法启动的问题
- 修复:修复JWT集成示例中版本升级API的变更
- 优化:优化启动时字符画打印
@@ -409,7 +429,7 @@ sa-token-sso 单点登录:
- 新增:新增全局侦听器,可在用户登陆、注销、被踢下线等关键性操作时进行一些AOP操作 **[重要]**
### 2021-4-12 @v1.16.0
### v1.16.0 @2021-4-12
- 新增:新增账号封禁功能,指定时间内账号无法登陆 **[重要]**
- 新增:核心包脱离`ServletAPI`,彻底零依赖! **[重要]**
- 新增:新增基于`ThreadLocal`的上下文容器 **[重要]**
@@ -420,7 +440,7 @@ sa-token-sso 单点登录:
- 文档:新增推荐公众号列表
### 2021-3-23 @v1.15.0
### v1.15.0 @2021-3-23
- 新增:文档添加源码涉及技术栈说明
- 优化:优化路由拦截器模块文档,更简洁的示例
- 修复:修复非web环境下的错误提示,Request->Response
@@ -440,7 +460,7 @@ sa-token-sso 单点登录:
- `SaRouteInterceptor`去出冗余API,详情参考路由鉴权部分
### 2021-3-12 @v1.14.0
### v1.14.0 @2021-3-12
- 新增:新增`SaLoginModel`登录参数Model,适配 [记住我] 模式 **[重要]**
- 新增:新增 `StpUtil.login()` 时指定token有效期,可灵活控制用户的一次登录免验证时长
- 新增:新增Cookie时间判断,在`timeout`设置为-1时,`Cookie`有效期将为`Integer.MAX_VALUE` **[重要]**
@@ -458,7 +478,7 @@ sa-token-sso 单点登录:
- 文档:优化文档,部分模块添加图片说明
### 2021-2-9 @v1.13.0
### v1.13.0 @2021-2-9
- 优化:优化源码注释与文档
- 新增:文档集成Gitalk评论系统
- 优化:源码包`Maven`版本号更改为变量形式
@@ -473,7 +493,7 @@ sa-token-sso 单点登录:
- 新增:完善分布式会话的文档说明
### 2021-1-12 @v1.12.0
### v1.12.0 @2021-1-12
- 新增:提供JWT集成示例 **[重要]**
- 新增:新增路由式鉴权,可方便的根据路由匹配鉴权 **[重要]**
- 新增:新增身份临时切换功能,可在一个代码段内将会话临时切换为其它账号 **[重要]**
@@ -482,23 +502,23 @@ sa-token-sso 单点登录:
- 升级:v1.12.1,新增`SaRouterUtil`工具类,更方便的路由鉴权 **[重要]**
### 2021-1-10 @v1.11.0
### v1.11.0 @2021-1-10
- 新增:提供AOP注解鉴权方案 **[重要]**
- 优化自动生成token的算法
### 2021-1-9 @v1.10.0
### v1.10.0 @2021-1-9
- 新增:提供查询所有会话方案 **[重要]**
- 修复:修复token设置为永不过期时无法正常被顶下线的bug,感谢github用户 @zjh599245299 提出的bug
### 2021-1-6 @v1.9.0
### v1.9.0 @2021-1-6
- 优化:`spring-boot-starter-data-redis``2.3.7.RELEASE` 改为 `2.3.3.RELEASE`
- 修复:补上注解拦截器里漏掉验证`@SaCheckRole`的bug
- 新增:新增同端互斥登录,像QQ一样手机电脑同时在线,但是两个手机上互斥登录 **[重要]**
### 2021-1-2 @v1.8.0
### v1.8.0 @2021-1-2
- 优化:优化源码注释
- 修复:修复部分文档错别字
- 修复:修复项目文件夹名称错误
@@ -517,7 +537,7 @@ sa-token-sso 单点登录:
- 升级:开源协议修改为`Apache-2.0`
### 2020-12-24 @v1.7.0
### v1.7.0 @2020-12-24
- 优化:项目架构改为maven多模块形式,方便增加新模块 **[重要]**
- 优化:与`springboot`的集成改为`springboot-starter`模式,无需`@SaTokenSetup`注解即可完成自动装配 **[重要]**
- 新增:新增`activity-timeout`配置,可控制token临时过期与续签功能 **[重要]**
@@ -527,13 +547,13 @@ sa-token-sso 单点登录:
- 修复:修复文档首页样式问题
### 2020-12-17 @v1.6.0
### v1.6.0 @2020-12-17
- 新增:花式token生成方案 **[重要]**
- 优化:优化`readme.md`
- 修复:修复`SaCookieOper``SaTokenAction`无法自动注入的问题
### 2020-12-16 @v1.5.1
### v1.5.1 @2020-12-16
- 新增:细化未登录异常类型,提供五种场景值:未提供token、token无效、token已过期 、token已被顶下线、token已被踢下线 **[重要]**
- 修复:修复`StpUtil.getSessionByLoginId(String loginId)`方法转换key出错的bug,感谢群友 @(#°Д°)、@一米阳光 发现的bug
- 优化:修改方法`StpUtil.getSessionByLoginId(Object loginId)`的isCreate值默认为true
@@ -547,7 +567,7 @@ sa-token-sso 单点登录:
- 升级:开源协议修改为`MIT`
### 2020-9-7 @v1.4.0
### v1.4.0 @2020-9-7
- 优化:修改一些函数、变量名称,使其更符合阿里java代码规范
- 优化:`tokenValue`的读取优先级改为:`request` > `body` > `header` > `cookie` **[重要]**
- 新增:新增`isReadCookie`配置,决定是否从`cookie`里读取`token`信息
@@ -556,7 +576,7 @@ sa-token-sso 单点登录:
- 修复:修复文档部分错误,修正群号码
### 2020-5-2 @v1.3.0
### v1.3.0 @2020-5-2
- 新增:新增 `StpUtil.checkLogin()` 方法,更符合语义化的鉴权方法
- 新增:注册拦截器时可设置 `StpLogic` ,方便不同模块不同鉴权方式
- 新增:抛出异常时增加 `loginType` 区分,方便多账号体系鉴权处理
@@ -565,14 +585,14 @@ sa-token-sso 单点登录:
- 新增:新增文档的友情链接
### 2020-3-7 @v1.2.0
### v1.2.0 @2020-3-7
- 新增:新增注解式验证,可在路由方法中使用注解进行权限验证 **[重要]**
- 参考:[注解式验证](use/at-check)
### 2020-2-12 @v1.1.0
### v1.1.0 @2020-2-12
- 修复:修复`StpUtil.getLoginId(T defaultValue)`取值转换错误的bug
### 2020-2-4 @v1.0.0
### v1.0.0 @2020-2-4
- 第一个版本出炉
+1
View File
@@ -13,6 +13,7 @@
- sa-token-redis-fastjsonRedis集成包,使用 fastjson 序列化方式。
- sa-token-redis-fastjson2Redis集成包,使用 fastjson2 序列化方式。
- sa-token-redisson-jacksonRedis集成包,Redisson客户端使用,jackson 序列化方式。
- sa-token-redisson-jackson2:通用 redisson 集成方案 spring, solon, jfinal 等都可用)。
有关 Redis 集成,详细参考:[集成Redis](/up/integ-redis),更多存储方式欢迎提交PR
+1 -1
View File
@@ -10,7 +10,7 @@
比如:用户账号增删改查维护、登录日志统计、新增用户数据报表、新增 Client 应用接入域名配置……等等,
仍需要大量的开发时间。
为此,我们特意准备了项目:[[ Sa-Sso-Pro 单点登录商业版 ]](http://sa-pro.dev33.cn/index.html?hmsr=sa-token)
为此,我们特意准备了项目:[[ Sa-Sso-Pro 单点登录商业版 ]](http://sa-pro.dev33.cn?hmsr=sa-token)
项目集成了单点登录常见技术点, 绝大多数功能无需二次开发,直接可用,<b style="color: #FF5722;">可大大缩短您的项目接入单点登录的开发周期</b>。
+2 -2
View File
@@ -5,14 +5,14 @@
---
### 正式版本
v1.34.0 正式版,可上生产:
v1.36.0 正式版,可上生产:
``` xml
<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.34.0</version>
<version>1.36.0</version>
</dependency>
```
+24
View File
@@ -329,3 +329,27 @@ body {
}
.main-box details p{padding: 0 14px;}
/* 顶部广告 */
#main .top-ad-box{padding: 0.5em 1em; font-size: 12px; margin-bottom: 30px; background-color: rgba(0, 0, 0, 0.04);}
#main .top-ad-box a{border-bottom: 0px;}
#main .top-ad-box a:hover{border-bottom: 0px;}
#main .top-ad-box a img{border: 0px #ddd solid; width: 100%; /* max-height: 80px; */
border-radius: 2px; transition: all 0.2s;}
#main .top-ad-box a img:hover{box-shadow: 0 0 20px #ddd;}
.ad-tips{color: #aaa;}
.ad-close{float: right;}
.ad-close:hover{cursor: pointer; text-decoration: underline; color: red;}
/* 帮助按钮 */
.help-btn{transition: all 0.2s;}
.help-btn:hover{box-shadow: 0 0 30px #aaa !important;}
.xiaozhushou-intro p{line-height: 16px;}
/* 按钮发光动画 */
.help-btn{animation: helpbtnanimation 3s infinite;}
@keyframes helpbtnanimation{
0%{box-shadow: 0 0 1px #42B983;}
50%{box-shadow: 0 0 20px #42B983;}
100%{box-shadow: 0 0 20px #FFF;}
}
+49 -1
View File
@@ -33,7 +33,7 @@ var myDocsifyPlugin = function(hook, vm) {
return html + footer;
});
// 钩子函数:次路由切换时数据全部加载完成后调用,没有参数。
// 钩子函数:次路由切换时数据全部加载完成后调用,没有参数。
hook.doneEach(function() {
// 功能3,给代码盒子,添加行数样式
@@ -59,6 +59,54 @@ var myDocsifyPlugin = function(hook, vm) {
if($('.zanzhu-count').length && $('.zanzhu-box table').length) {
$('.zanzhu-count').html($('.zanzhu-box table tr').length);
}
// 功能6:标题下面的广告
if(vm.route.path !== '/' && $(window).width() >= 800) {
var ad = `<p class="top-ad-box">
<span class="ad-tips">推广信息</span>
<span class="ad-tips ad-close">关闭</span>
<a href="http://sa-pro.dev33.cn?from=satop" target="_blank">
<img src="https://oss.dev33.cn/sa-token/ad/sa-sso-pro-x.png" />
</a>
</p>`;
// 没有下划线就先补个下划线
// if($('#main h1').next().prop('tagName') !== 'HR') {
// $('#main h1').after('<hr/>');
// }
// 如果一周内用户点击过关闭广告,则不再展现
let allowJg = 1000 * 60 * 60 * 24 * 7;
// allowJg = 1000 * 10;
try{
const closeAdTime = localStorage.closeAdTime;
if(closeAdTime) {
// 点击广告关闭的时间,和当前时间的差距
const closeAdJg = new Date().getTime() - parseInt(closeAdTime);
// 差距小于七天,不再展示
if(closeAdJg < allowJg) {
console.log('not show ad ...');
return;
}
}
}catch(e){
console.error(e);
}
// 添加广告
$('#main h1').after(ad);
// 添加关闭事件
$('.top-ad-box .ad-close').click(function(){
console.log('关闭广告');
// $('.top-ad-box').slideUp(); // 折叠收起
$(".top-ad-box").fadeOut(1000); // 淡出效果
layer.msg('一周内不再展现此信息')
localStorage.closeAdTime = new Date().getTime();
})
}
});
// 钩子函数:初始化并第一次加载完成数据后调用,没有参数。
+259
View File
@@ -0,0 +1,259 @@
//
// 声明 docsify 插件
var isStarPlugin = function(hook, vm) {
// 钩子函数:解析之前执行
hook.beforeEach(function(content) {
return content;
});
// 钩子函数:每次路由切换时,解析内容之后执行
hook.afterEach(function(html) {
return html;
});
// 钩子函数:每次路由切换时数据全部加载完成后调用,没有参数。
hook.doneEach(function() {
isStarRepo(vm);
});
// 钩子函数:初始化并第一次加载完成数据后调用,没有参数。
hook.ready(function() {
});
}
// 应用参数
const client_id = '0cc618beb08db99bff50e500e38c2144d95ada9abb51c00c44592726ecd583f4';
const client_secret = 'xxx';
const redirect_uri = 'https://sa-token.cc/doc.html';
const docDomain = 'sa-token.cc';
// const redirect_uri = 'http://127.0.0.1:8848/sa-token-doc/doc.html';
// const docDomain = '127.0.0.1:8848';
// 检查成功后,多少天不再检查
const allowDisparity = 1000 * 60 * 60 * 24 * 30 * 3;
// const allowDisparity = 1000 * 10;
// 判断当前是否已 star
function isStarRepo(vm) {
// 非PC端不检查
if(document.body.offsetWidth < 800) {
console.log('small screen ...');
return;
}
// 判断是否在主域名下
if(location.host !== docDomain) {
console.log('not domain, no check...');
return;
}
// 判断是否近期已经判断过了
try{
const isStarRepo = localStorage.isStarRepo;
if(isStarRepo) {
// 记录 star 的时间,和当前时间的差距
const disparity = new Date().getTime() - parseInt(isStarRepo);
// 差距小于一月,不再检测,大于一月,再检测一下
if(disparity < allowDisparity) {
console.log('checked ...');
return;
}
}
}catch(e){
console.error(e);
}
// 白名单路由不判断
const whiteList = ['/a', '/more/link', '/more/demand-commit', '/more/join-group', '/more/sa-token-donate',
'/sso/sso-pro', '/more/update-log', '/more/common-questions', '/fun/sa-token-test', '/fun/issue-template'];
if(whiteList.indexOf(vm.route.path) >= 0 && getParam('code') === null) {
console.log('white route ...');
return;
}
// 开始获取 code
$('body').css({'overflow': 'hidden'});
getCode();
}
// 去请求授权
function getCode() {
// 检查url中是否有code
const code = getParam('code');
if(code) {
// 有 code,进一步去请求 access_token
getAccessToken(code);
} else {
// 不存在code,弹窗提示询问
confirmStar();
}
}
// 弹窗提示点 star
function confirmStar() {
// 弹窗提示文字
const tipStr = `
<div>
<p><b>同学来支持一下 Sa-Token 为项目点个 star </b></p>
<div>仅需两步即可完成<br>
<div>1打开 Sa-Token <a href="https://gitee.com/dromara/sa-token" target="_blank">开源仓库主页</a> star </div>
<div>2点击下方 [ 同意授权检测 ] 按钮同意 Sa-Token 获取 API 权限进行检测<a href="javascript:authDetails();" style="text-decoration: none;"></a></div>
</div>
<p><b>本章节文档将在 star 后正常开放展示</b></p>
<p style="color: green;">开源不易希望您不吝支持激励开源项目走的更加长远 😇😇😇</p>
</div>
`;
const index = layer.confirm(tipStr, {
title: '提示',
btn: ['同意授权检测'],
// btn: ['同意授权检测', '暂时不要,我先看看文档'],
area: '460px',
offset: '25%',
closeBtn: false
},
function(index) {
//
layer.close(index);
// 用户点了确认,去 gitee 官方请求授权获取
goAuth();
}
);
// 源码注释提示
const closeLayer =
`
<!--
f12 控制台 执行一下
localStorage.isStarRepo = new Date().getTime()
即可取消弹窗 执行完刷新一下页面
-->
`;
$('#layui-layer' + index).prepend(closeLayer)
}
// 跳转到 gitee 授权界面
function goAuth() {
const authUrl = "https://gitee.com/oauth/authorize" +
"?client_id=" + client_id +
"&redirect_uri=" + redirect_uri +
"&response_type=code";
location.href = authUrl;
}
// 获取 access_token
function getAccessToken(code) {
// 根据 code 获取 access_token
$.ajax({
url: 'https://sa-token.cc/server/oauth/token',
method: 'post',
data: {
grant_type: 'authorization_code',
code: code,
client_id: client_id,
redirect_uri: redirect_uri,
client_secret: client_secret,
},
success: function(res) {
// 如果返回的不是 200
if(res.code !== 200) {
return layer.alert(res.msg, {closeBtn: false}, function(){
// 刷新url,去掉 code 参数
location.href = 'doc.html';
});
}
// 拿到 access_token
const access_token = res.access_token;
// 根据 access_token 判断是否 star 了仓库
$.ajax({
url: 'https://gitee.com/api/v5/user/starred/dromara/sa-token',
method: 'get',
data: {
access_token: access_token
},
success: function(res) {
// success 回调即代表已经 stargitee API 请求体不返回任何数据
console.log('-> stared ...');
// 记录本次检查时间
localStorage.isStarRepo = new Date().getTime();
//
layer.alert('感谢你的支持 ❤️ ❤️ ❤️ ,Sa-Token 将努力变得更加完善!', function(index) {
layer.close(index);
// 刷新url,去掉 code 参数
location.href = location.href.replace("?code=" + code, '');
})
},
error: function(e) {
// console.log('ff请求错误 ', e);
// 如下返回,代表没有 star
if(e.statusText = 'Not Found'){
console.log('not star ...');
layer.alert('未检测到 star 数据...', {closeBtn: false}, function() {
// 刷新url,去掉 code 参数
location.href = location.href.replace("?code=" + code, '');
});
}
}
});
},
error: function(e) {
console.log('请求错误 ', e);
// 如果请求地址有错,可能是服务器宕机了,暂停一天检测
if(e.status === 0 || e.status === 502) {
return layer.alert(JSON.stringify(e), {closeBtn: false}, function(){
// 一天内不再检查
const ygTime = allowDisparity - (1000 * 60 * 60 * 24);
localStorage.isStarRepo = new Date().getTime() - ygTime;
// 刷新 url,去掉 code 参数
location.href = location.href.replace("?code=" + code, '');
});
}
// 无效授权,可能是 code 无效
const errorMsg = (e.responseJSON && e.responseJSON.error) || JSON.stringify(e);
if(errorMsg == 'invalid_grant') {
console.log('无效code', code);
}
layer.alert('check error... ' + errorMsg, function(index) {
layer.close(index);
// 刷新url,去掉 code 参数
let url = location.href.replace("?code=" + code, '');
url = url.replace("&code=" + code, '');
location.href = url;
});
}
})
}
// 疑问
function authDetails() {
const str = "用于检测的凭证信息将仅保存你的浏览器本地,Sa-Token 文档已完整开源,源码可查";
alert(str);
}
// 获取 url 携带的参数
function getParam(name, defaultValue){
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == name){return pair[1];}
}
return(defaultValue == undefined ? null : defaultValue);
}
@@ -0,0 +1,70 @@
@charset "utf-8";
/* CSS Document */
/* ry盒子 总区域 */
.ry-kuai{
padding-left: 0;
padding-right: 0;
}
/* ry盒子 灰色区域 */
.ry-box{
padding-top: 70px;
padding-bottom: 170px;
background-color: #eee;
position: relative;
overflow: hidden;
}
/* 轮播图容器 */
.ry-box .swiper {
width: 100%;
height: 100%;
}
.ry-box .swiper-slide {
text-align: center;
font-size: 18px;
width: 750px;
height: 500px;
/* cursor: pointer; */
}
.ry-box .swiper-slide-tx1{
width: 450px;
}
.ry-box .swiper-slide img {
height: 100%;
box-shadow: 0 0 20px #ccc;
transition: box-shadow 0.2s;
}
.ry-box .swiper-slide img:hover{
box-shadow: 0 0 40px #999;
}
.ry-box .swiper-slide p{
display: inline-block;
font-size: 16px;
margin-top: 30px;
color: #222;
}
/* 分页器样式 */
.ry-box .swiper-pagination{bottom: -140px;}
.ry-box .swiper-pagination .swiper-pagination-bullet{width: 18px; height: 18px; line-height: 18px; color: #FFF; font-size: 12px;}
/* 图片放大动画 */
.ry-box .swiper-slide img{
transition: 300ms;
transform: scale(0.8);
}
.ry-box .swiper-slide-active img,
.ry-box .swiper-slide-duplicate-active img{
transform: scale(1);
}
/* 阴影 */
/* .ry-img-yinying{
width: 50%; height: 10px; border-radius: 50%;
background-color: rgba(0, 0, 0, 0.8);
box-shadow: 0 0 50px #333;
margin: auto;
} */
@@ -0,0 +1,59 @@
function initSwiper () {
if(window.swiper){
return;
}
window.swiper = new Swiper(".mySwiper", {
// 最大容纳的slide数量,auto=自动
slidesPerView: "auto",
// 主角 slide 居中
centeredSlides: true,
// 使左右 slide 贴合容器
// centeredSlidesBounds: true,
// 循环
loop: true,
// 自动播放
autoplay: {
// 3秒切换一次
delay: 3000,
},
// slide 间距
spaceBetween: 80,
// 点击 slide 时,过渡到这个 slide
slideToClickedSlide: true,
// 切换效果 slide=普通位移、fade=淡入、cube=方块、coverflow=3d流、flip=3d翻转、cards=卡片式、creative=创意性
effect: 'coverflow',
// 抓取时,鼠标变小手
grabCursor: true,
// 分页器
pagination: {
el: ".swiper-pagination",
// 点击时切换 slide
clickable: true,
// 分页器样式,bullets=原点,fraction=分式,progressbar=进度条,custom=自定义
type: "bullets",
// 点击小点,切换 slide
clickable :true,
// 将按钮从小点变成数字
renderBullet: function (index, className) {
return '<span class="' + className + '">' + (index + 1) + '</span>';
},
},
// 左右切换按钮
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
});
}
$(function(){
initSwiper();
})
// 滚动到 swiper 时,再加载
// $(document).scroll(function(){
// // 页面滚动条高度 > ry盒子到顶部距离 + window 视口高度 时,swiper出现
// if($(document).scrollTop() > $('.ry-kuai').offset().top - $(window).height()) {
// initSwiper();
// }
// })
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -63,4 +63,5 @@ public class SaTokenConfigure {
gfuPSwZsnUhwgz08GTCH4wOgasWtc3odP4HLwXJ7NDGOximTvT4OlW19zeLH
```
!> **更改了 token 生成策略但是不生效?**<br> 把 Redis 中的旧数据清除掉再试试
+1
View File
@@ -23,6 +23,7 @@
<module>sa-token-redis-fastjson</module>
<module>sa-token-redis-fastjson2</module>
<module>sa-token-redisson-jackson</module>
<module>sa-token-redisson-jackson2</module>
<module>sa-token-redisx</module>
<module>sa-token-alone-redis</module>
<module>sa-token-dialect-thymeleaf</module>
@@ -74,10 +74,6 @@ public class SaAloneRedisInject implements EnvironmentAware{
if(saTokenDao == null || saTokenDao instanceof SaTokenDaoDefaultImpl) {
return;
}
// 如果配置文件不包含相关配置则不进行任何操作
if(environment.getProperty(ALONE_PREFIX + ".host") == null) {
return;
}
// ------------------- 开始注入
@@ -961,7 +961,7 @@ public class SaOAuth2Template {
return SaManager.getConfig().getTokenName() + ":oauth2:client-token:" + clientToken;
}
/**
* 拼接keyPast-Token 索引
* 拼接keyClient-Token 索引
* @param clientId clientId
* @return key
*/
@@ -0,0 +1,100 @@
## sa-token-redisson-jackson2
此扩展,不与生态绑定。可用于不同的生态。
### 1、例 solon 集成
添加关键依赖
```xml
<dependencies>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisson-jackson2</artifactId>
<version>${sa-token.version}</version>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>redisson-solon-plugin</artifactId>
<version>${solon.version}</version>
</dependency>
</dependencies>
```
添加 dao 配置
```yaml
sa-token-dao:
config: |
singleServerConfig:
password: "123456"
address: "redis://localhost:6379"
database: 0
```
开始组装
```java
@Configuration
public class SaTokenConfigure {
/**
* 构造 RedissonClient
* */
@Bean
public RedissonClient saTokenDaoInit(@Inject("${sa-token-dao}") RedissonSupplier supplier) {
return supplier.get();
}
/**
* 构建 SaTokenDao
* */
@Bean
public SaTokenDao saTokenDaoInit(RedissonClient redissonClient) {
return new SaTokenDaoRedissonJackson(redissonClient);
}
}
```
### 2、例 springboot 集成
添加关键依赖
```xml
<dependencies>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisson-jackson2</artifactId>
<version>${sa-token.version}</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
</dependencies>
```
添加 dao 配置
```yaml
spring.redis:
redisson:
file: classpath:redisson.yml
```
开始组装
```java
@Configuration
public class SaTokenConfigure {
/**
* 构建 SaTokenDao
* */
@Bean
public SaTokenDao saTokenDaoInit(RedissonClient redissonClient) {
return new SaTokenDaoRedissonJackson(redissonClient);
}
}
```
@@ -0,0 +1,48 @@
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-plugin</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>jar</packaging>
<name>sa-token-redisson-jackson2</name>
<artifactId>sa-token-redisson-jackson2</artifactId>
<description>sa-token integrate redisson (to jackson)</description>
<dependencies>
<!-- sa-token-spring-boot-starter -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
</dependency>
<!-- Redisson 相关操作API -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<optional>true</optional>
</dependency>
<!-- jackson-datatype-jsr310 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,47 @@
/*
* 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.dao;
import cn.dev33.satoken.session.SaSession;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* Jackson定制版SaSession忽略 timeout 等属性的序列化
*
* @author click33
* @since 1.34.0
*/
@JsonIgnoreProperties({"timeout"})
public class SaSessionForJacksonCustomized extends SaSession {
/**
*
*/
private static final long serialVersionUID = -7600983549653130681L;
public SaSessionForJacksonCustomized() {
super();
}
/**
* 构建一个Session对象
* @param id Session的id
*/
public SaSessionForJacksonCustomized(String id) {
super(id);
}
}
@@ -0,0 +1,292 @@
/*
* 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.dao;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.redisson.api.RBatch;
import org.redisson.api.RBucket;
import org.redisson.api.RBucketAsync;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.codec.JsonJacksonCodec;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token 持久层实现 [ Redisson客户端Redis存储Jackson序列化 ]
*
* @author 疯狂的狮子Li
* @author noear
* @since 1.34.0
*/
public class SaTokenDaoRedissonJackson implements SaTokenDao {
public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static final String DATE_PATTERN = "yyyy-MM-dd";
public static final String TIME_PATTERN = "HH:mm:ss";
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DATE_PATTERN);
public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(TIME_PATTERN);
/**
* ObjectMapper 对象 ( public 作用域暴露出此对象方便开发者二次更改配置)
*
* <p> 例如
* <pre>
* SaTokenDaoRedisJackson redisJackson = (SaTokenDaoRedisJackson) SaManager.getSaTokenDao();
* redisJackson.objectMapper.xxx = xxx;
* </pre>
* </p>
*/
public final ObjectMapper objectMapper;
/**
* 序列化方式
*/
public final Codec codec;
/**
* redisson 客户端
*/
public final RedissonClient redissonClient;
public SaTokenDaoRedissonJackson(RedissonClient redissonClient) {
this.objectMapper = new ObjectMapper();
this.objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
// 配置[忽略未知字段]
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 配置[时间类型转换]
JavaTimeModule timeModule = new JavaTimeModule();
// LocalDateTime序列化与反序列化
timeModule.addSerializer(new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
// LocalDate序列化与反序列化
timeModule.addSerializer(new LocalDateSerializer(DATE_FORMATTER));
timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DATE_FORMATTER));
// LocalTime序列化与反序列化
timeModule.addSerializer(new LocalTimeSerializer(TIME_FORMATTER));
timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(TIME_FORMATTER));
this.objectMapper.registerModule(timeModule);
// 重写 SaSession 生成策略
SaStrategy.instance.createSession = (sessionId) -> new SaSessionForJacksonCustomized(sessionId);
// 开始初始化相关组件
this.codec = new JsonJacksonCodec(objectMapper);
this.redissonClient = redissonClient;
}
/**
* 获取Value如无返空
*/
@Override
public String get(String key) {
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
return rBucket.get();
}
/**
* 写入Value并设定存活时间 (单位: )
*/
@Override
public void set(String key, String value, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
// 判断是否为永不过期
if(timeout == SaTokenDao.NEVER_EXPIRE) {
RBucket<String> bucket = redissonClient.getBucket(key, codec);
bucket.set(value);
} else {
RBatch batch = redissonClient.createBatch();
RBucketAsync<String> bucket = batch.getBucket(key, codec);
bucket.setAsync(value);
bucket.expireAsync(Duration.ofSeconds(timeout));
batch.execute();
}
}
/**
* 修修改指定key-value键值对 (过期时间不变)
*/
@Override
public void update(String key, String value) {
long expire = getTimeout(key);
// -2 = 无此键
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
this.set(key, value, expire);
}
/**
* 删除Value
*/
@Override
public void delete(String key) {
redissonClient.getBucket(key, codec).delete();
}
/**
* 获取Value的剩余存活时间 (单位: )
*/
@Override
public long getTimeout(String key) {
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
long timeout = rBucket.remainTimeToLive();
return timeout < 0 ? timeout : timeout / 1000;
}
/**
* 修改Value的剩余存活时间 (单位: )
*/
@Override
public void updateTimeout(String key, long timeout) {
// 判断是否想要设置为永久
if(timeout == SaTokenDao.NEVER_EXPIRE) {
long expire = getTimeout(key);
if(expire == SaTokenDao.NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.set(key, this.get(key), timeout);
}
return;
}
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
rBucket.expire(Duration.ofSeconds(timeout));
}
/**
* 获取Object如无返空
*/
@Override
public Object getObject(String key) {
RBucket<Object> rBucket = redissonClient.getBucket(key, codec);
return rBucket.get();
}
/**
* 写入Object并设定存活时间 (单位: )
*/
@Override
public void setObject(String key, Object object, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
// 判断是否为永不过期
if(timeout == SaTokenDao.NEVER_EXPIRE) {
RBucket<Object> bucket = redissonClient.getBucket(key, codec);
bucket.set(object);
} else {
RBatch batch = redissonClient.createBatch();
RBucketAsync<Object> bucket = batch.getBucket(key, codec);
bucket.setAsync(object);
bucket.expireAsync(Duration.ofSeconds(timeout));
batch.execute();
}
}
/**
* 更新Object (过期时间不变)
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
// -2 = 无此键
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
this.setObject(key, object, expire);
}
/**
* 删除Object
*/
@Override
public void deleteObject(String key) {
redissonClient.getBucket(key, codec).delete();
}
/**
* 获取Object的剩余存活时间 (单位: )
*/
@Override
public long getObjectTimeout(String key) {
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
long timeout = rBucket.remainTimeToLive();
return timeout < 0 ? timeout : timeout / 1000;
}
/**
* 修改Object的剩余存活时间 (单位: )
*/
@Override
public void updateObjectTimeout(String key, long timeout) {
// 判断是否想要设置为永久
if(timeout == SaTokenDao.NEVER_EXPIRE) {
long expire = getObjectTimeout(key);
if(expire == SaTokenDao.NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.setObject(key, this.getObject(key), timeout);
}
return;
}
RBucket<Object> rBucket = redissonClient.getBucket(key, codec);
rBucket.expire(Duration.ofSeconds(timeout));
}
/**
* 搜索数据
*/
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
Stream<String> stream = redissonClient.getKeys().getKeysStreamByPattern(prefix + "*" + keyword + "*");
List<String> list = stream.collect(Collectors.toList());
return SaFoxUtil.searchList(list, start, size, sortType);
}
}
+27 -6
View File
@@ -42,17 +42,38 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>snack3</artifactId>
<scope>provided</scope>
</dependency>
<!-- redisx + snack3 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>redisx</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>snack3</artifactId>
<scope>provided</scope>
</dependency>
<!-- redisson + jackson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<scope>provided</scope>
</dependency>
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<!-- jackson-datatype-jsr310 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -35,7 +35,7 @@ import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempInterface;
import org.noear.solon.Solon;
import org.noear.solon.core.AopContext;
import org.noear.solon.core.AppContext;
import org.noear.solon.core.Plugin;
/**
@@ -45,7 +45,7 @@ import org.noear.solon.core.Plugin;
public class XPluginImp implements Plugin {
@Override
public void start(AopContext context) {
public void start(AppContext context) {
// Sa-Token 日志输出 Bean
context.getBeanAsync(SaLog.class, bean -> {
SaManager.setLog(bean);
@@ -60,7 +60,7 @@ public class XPluginImp implements Plugin {
});
}
private void beanInitDo(AopContext context) {
private void beanInitDo(AppContext context) {
// 注入上下文Bean
SaManager.setSaTokenContext(new SaContextForSolon());
@@ -0,0 +1,47 @@
/*
* 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.solon.dao;
import cn.dev33.satoken.session.SaSession;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* Jackson定制版SaSession忽略 timeout 等属性的序列化
*
* @author click33
* @since 1.34.0
*/
@JsonIgnoreProperties({"timeout"})
public class SaSessionForJacksonCustomized extends SaSession {
/**
*
*/
private static final long serialVersionUID = -7600983549653130681L;
public SaSessionForJacksonCustomized() {
super();
}
/**
* 构建一个Session对象
* @param id Session的id
*/
public SaSessionForJacksonCustomized(String id) {
super(id);
}
}
@@ -0,0 +1,291 @@
/*
* 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.solon.dao;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaFoxUtil;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.redisson.api.RBatch;
import org.redisson.api.RBucket;
import org.redisson.api.RBucketAsync;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.codec.JsonJacksonCodec;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Sa-Token 持久层实现 [ Redisson客户端Redis存储Jackson序列化 ]
*
* @author 疯狂的狮子Li
* @author noear
* @since 1.34.0
*/
public class SaTokenDaoOfRedissonJackson implements SaTokenDao {
public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static final String DATE_PATTERN = "yyyy-MM-dd";
public static final String TIME_PATTERN = "HH:mm:ss";
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DATE_PATTERN);
public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(TIME_PATTERN);
/**
* ObjectMapper 对象 ( public 作用域暴露出此对象方便开发者二次更改配置)
*
* <p> 例如
* <pre>
* SaTokenDaoRedisJackson redisJackson = (SaTokenDaoRedisJackson) SaManager.getSaTokenDao();
* redisJackson.objectMapper.xxx = xxx;
* </pre>
* </p>
*/
public final ObjectMapper objectMapper;
/**
* 序列化方式
*/
public final Codec codec;
/**
* redisson 客户端
*/
public final RedissonClient redissonClient;
public SaTokenDaoOfRedissonJackson(RedissonClient redissonClient) {
this.objectMapper = new ObjectMapper();
this.objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
// 配置[忽略未知字段]
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 配置[时间类型转换]
JavaTimeModule timeModule = new JavaTimeModule();
// LocalDateTime序列化与反序列化
timeModule.addSerializer(new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
// LocalDate序列化与反序列化
timeModule.addSerializer(new LocalDateSerializer(DATE_FORMATTER));
timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DATE_FORMATTER));
// LocalTime序列化与反序列化
timeModule.addSerializer(new LocalTimeSerializer(TIME_FORMATTER));
timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(TIME_FORMATTER));
this.objectMapper.registerModule(timeModule);
// 重写 SaSession 生成策略
SaStrategy.instance.createSession = (sessionId) -> new SaSessionForJacksonCustomized(sessionId);
// 开始初始化相关组件
this.codec = new JsonJacksonCodec(objectMapper);
this.redissonClient = redissonClient;
}
/**
* 获取Value如无返空
*/
@Override
public String get(String key) {
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
return rBucket.get();
}
/**
* 写入Value并设定存活时间 (单位: )
*/
@Override
public void set(String key, String value, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
// 判断是否为永不过期
if(timeout == SaTokenDao.NEVER_EXPIRE) {
RBucket<String> bucket = redissonClient.getBucket(key, codec);
bucket.set(value);
} else {
RBatch batch = redissonClient.createBatch();
RBucketAsync<String> bucket = batch.getBucket(key, codec);
bucket.setAsync(value);
bucket.expireAsync(Duration.ofSeconds(timeout));
batch.execute();
}
}
/**
* 修修改指定key-value键值对 (过期时间不变)
*/
@Override
public void update(String key, String value) {
long expire = getTimeout(key);
// -2 = 无此键
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
this.set(key, value, expire);
}
/**
* 删除Value
*/
@Override
public void delete(String key) {
redissonClient.getBucket(key, codec).delete();
}
/**
* 获取Value的剩余存活时间 (单位: )
*/
@Override
public long getTimeout(String key) {
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
long timeout = rBucket.remainTimeToLive();
return timeout < 0 ? timeout : timeout / 1000;
}
/**
* 修改Value的剩余存活时间 (单位: )
*/
@Override
public void updateTimeout(String key, long timeout) {
// 判断是否想要设置为永久
if(timeout == SaTokenDao.NEVER_EXPIRE) {
long expire = getTimeout(key);
if(expire == SaTokenDao.NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.set(key, this.get(key), timeout);
}
return;
}
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
rBucket.expire(Duration.ofSeconds(timeout));
}
/**
* 获取Object如无返空
*/
@Override
public Object getObject(String key) {
RBucket<Object> rBucket = redissonClient.getBucket(key, codec);
return rBucket.get();
}
/**
* 写入Object并设定存活时间 (单位: )
*/
@Override
public void setObject(String key, Object object, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
// 判断是否为永不过期
if(timeout == SaTokenDao.NEVER_EXPIRE) {
RBucket<Object> bucket = redissonClient.getBucket(key, codec);
bucket.set(object);
} else {
RBatch batch = redissonClient.createBatch();
RBucketAsync<Object> bucket = batch.getBucket(key, codec);
bucket.setAsync(object);
bucket.expireAsync(Duration.ofSeconds(timeout));
batch.execute();
}
}
/**
* 更新Object (过期时间不变)
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
// -2 = 无此键
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
this.setObject(key, object, expire);
}
/**
* 删除Object
*/
@Override
public void deleteObject(String key) {
redissonClient.getBucket(key, codec).delete();
}
/**
* 获取Object的剩余存活时间 (单位: )
*/
@Override
public long getObjectTimeout(String key) {
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
long timeout = rBucket.remainTimeToLive();
return timeout < 0 ? timeout : timeout / 1000;
}
/**
* 修改Object的剩余存活时间 (单位: )
*/
@Override
public void updateObjectTimeout(String key, long timeout) {
// 判断是否想要设置为永久
if(timeout == SaTokenDao.NEVER_EXPIRE) {
long expire = getObjectTimeout(key);
if(expire == SaTokenDao.NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.setObject(key, this.getObject(key), timeout);
}
return;
}
RBucket<Object> rBucket = redissonClient.getBucket(key, codec);
rBucket.expire(Duration.ofSeconds(timeout));
}
/**
* 搜索数据
*/
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
Stream<String> stream = redissonClient.getKeys().getKeysStreamByPattern(prefix + "*" + keyword + "*");
List<String> list = stream.collect(Collectors.toList());
return SaFoxUtil.searchList(list, start, size, sortType);
}
}
@@ -26,6 +26,7 @@ import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.strategy.SaStrategy;
import org.noear.solon.Solon;
import org.noear.solon.core.handle.*;
import org.noear.solon.core.route.RoutingTable;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -136,6 +137,13 @@ public class SaTokenFilter implements SaFilter, Filter { //之所以改名,为
try {
//查找当前主处理
Handler mainHandler = Solon.app().router().matchMain(ctx);
if (mainHandler instanceof Gateway) {
//支持网关处理
Gateway gateway = (Gateway) mainHandler;
RoutingTable<Handler> mainRouting = gateway.getMainRouting();
MethodType method = MethodTypeUtil.valueOf(ctx.method());
mainHandler = mainRouting.matchOne(ctx.pathNew(), method);
}
Action action = (mainHandler instanceof Action ? (Action) mainHandler : null);
//1.执行前置处理主要是一些跨域之类的
@@ -144,16 +152,16 @@ public class SaTokenFilter implements SaFilter, Filter { //之所以改名,为
}
//先路径过滤下包括了静态文件
Handler finalMainHandler = mainHandler;
SaRouter.match(includeList).notMatch(excludeList).check(r -> {
//2.执行注解处理
if(authAnno(action)) {
//3.执行规则处理如果没有被 @SaIgnore 忽略
auth.run(mainHandler);
auth.run(finalMainHandler);
}
});
} catch (StopMatchException e) {
// StopMatchException 异常代表停止匹配进入Controller
} catch (SaTokenException e) {
// 1. 获取异常处理策略结果
Object result;
@@ -26,6 +26,7 @@ import cn.dev33.satoken.strategy.SaStrategy;
import org.noear.solon.core.handle.*;
import org.noear.solon.core.route.RouterInterceptor;
import org.noear.solon.core.route.RouterInterceptorChain;
import org.noear.solon.core.route.RoutingTable;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -185,6 +186,14 @@ public class SaTokenInterceptor implements RouterInterceptor {
@Override
public void doIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {
try {
if (mainHandler instanceof Gateway) {
//支持网关处理
Gateway gateway = (Gateway) mainHandler;
RoutingTable<Handler> mainRouting = gateway.getMainRouting();
MethodType method = MethodTypeUtil.valueOf(ctx.method());
mainHandler = mainRouting.matchOne(ctx.pathNew(), method);
}
Action action = (mainHandler instanceof Action ? (Action) mainHandler : null);
//1.执行前置处理主要是一些跨域之类的
@@ -193,16 +202,17 @@ public class SaTokenInterceptor implements RouterInterceptor {
}
//先路径过滤下不包括静态文件
Handler finalMainHandler = mainHandler;
SaRouter.match(includeList).notMatch(excludeList).check(r -> {
//2.执行注解处理
if(authAnno(action)) {
//3.执行规则处理如果没有被 @SaIgnore 忽略
auth.run(mainHandler);
auth.run(finalMainHandler);
}
});
} catch (StopMatchException e) {
// StopMatchException 异常代表停止匹配进入Controller
} catch (SaTokenException e) {
// 1. 获取异常处理策略结果
Object result;

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