...
 
Commits (19)
    https://gitcode.net/int/sa-token/-/commit/759dfc79cc72660b73dc11c1b859ac5dab320675 缩小请求权限范围 2023-08-24T12:58:45+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/195697c2b32f2f8e5cf9a6a2200666977d013981 更新赞助者名单 2023-08-24T13:00:50+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/13ff5c83062bc07374182703eb12fa8e8df519f2 Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-08-24T13:01:16+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/d59b27cc6629e3006528d30f1310b3a0c043de15 去除不必要的注释 2023-08-24T13:44:31+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/4c35f9e936f6b99209f25fee80f8f99b6ba30424 常见问答增加新问题 2023-08-30T11:26:27+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/5120cfa1bbc9c7410e5bfd9b075f7e8738101bf6 docs: 将「Q:开启了全局懒加载后,能启动项目,但是访问接口报未能获取有效的上下文处理器」问题链接加入前置的「Q:报错:未能获取有效的上下文处理器。」中 2023-09-01T11:19:01+08:00 Uncarbon 75737767+uncarbon97@users.noreply.github.com https://gitcode.net/int/sa-token/-/commit/8506f234aa93fa310155a4356998c62cf1dfde2d !276 docs: 将「Q:开启了全局懒加载后,能启动项目,但是访问接口报未能获取有效的上下文处理器」问题链接加入前置的「Q:报错:未能获取有效的上下文... 2023-09-01T03:23:32+00:00 孔明 2393584716@qq.com Merge pull request !276 from Uncarbon/dev https://gitcode.net/int/sa-token/-/commit/d1d5716ddc5b6c19046a0a7b2b55db89d5b1ffd3 update README.md. 2023-09-01T06:10:54+00:00 孔明 2393584716@qq.com Signed-off-by: <span data-trailer="Signed-off-by:" data-user="63962"><a href="https://gitcode.net/shengzhang_" title="2393584716@qq.com"><img alt="shengzhang_'s avatar" src="https://profile-avatar.csdnimg.cn/3c6b95cb4a6546dca842d46e4f60d5f6_shengzhang_.jpg!1" class="avatar s16 avatar-inline" title="shengzhang_"></a><a href="https://gitcode.net/shengzhang_" title="2393584716@qq.com">孔明</a> &lt;<a href="mailto:2393584716@qq.com" title="2393584716@qq.com">2393584716@qq.com</a>&gt;</span> https://gitcode.net/int/sa-token/-/commit/5c2d6076c96dac1795cac62093ca4addf22fd347 beautify qr 2023-09-02T15:33:51+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/31b410eadd0711a79f5b778c0a093a08159362a6 Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-09-02T15:34:24+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/e74a589b88d63d34446ea75d5fd3529a65e64dfa !277 docs: 「微服务」节文档完善 2023-09-02T07:39:53+00:00 Uncarbon 4840454+uncarbon97@user.noreply.gitee.com * docs: 「微服务」节文档格式完善 * docs: boot3版的依赖名未同步至「微服务」节中;「服务」<gl-emoji title="white right pointing backhand index" data-name="point_right" data-unicode-version="6.0">👉</gl-emoji>「服务间」 https://gitcode.net/int/sa-token/-/commit/c09f5ae20e8bb298f61b9a3be4857edfa387c515 ... 2023-09-03T12:51:58+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/56cb20aff6ce53d10fb16352f406d24bb30e23b1 增加友联 2023-09-03T12:52:13+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/fcf3cc43f48760ab3d3988de04f25ff6f9d789bf ... 2023-09-03T12:52:40+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/e76169864d2b932509ad288766c1364072ce2734 Solon 框架升为:2.5.3 2023-09-04T13:29:08+08:00 noear noear@live.cn https://gitcode.net/int/sa-token/-/commit/6dfa7508216117e16eddb659adeb9ab3f0594bf2 !278 Solon 框架升为:2.5.3 2023-09-04T09:30:31+00:00 刘潇 2393584716@qq.com Merge pull request !278 from 西东/dev https://gitcode.net/int/sa-token/-/commit/ac2d65042c1bfc4f7f79b260c6ae67c3eb97b6d6 update sa-token-doc/start/new-version.md. 2023-09-07T10:12:38+00:00 刘潇 2393584716@qq.com Signed-off-by: <span data-trailer="Signed-off-by:" data-user="63962"><a href="https://gitcode.net/shengzhang_" title="2393584716@qq.com"><img alt="shengzhang_'s avatar" src="https://profile-avatar.csdnimg.cn/3c6b95cb4a6546dca842d46e4f60d5f6_shengzhang_.jpg!1" class="avatar s16 avatar-inline" title="shengzhang_"></a><a href="https://gitcode.net/shengzhang_" title="2393584716@qq.com">刘潇</a> &lt;<a href="mailto:2393584716@qq.com" title="2393584716@qq.com">2393584716@qq.com</a>&gt;</span> https://gitcode.net/int/sa-token/-/commit/83268da0cb3730451477b45ace57974531da82be 优化文档 2023-09-12T19:26:28+08:00 click33 2393584716@qq.com https://gitcode.net/int/sa-token/-/commit/2cfb8df28aff0bb901723c8986db6484adc11181 Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-09-12T19:26:38+08:00 click33 2393584716@qq.com
......@@ -176,6 +176,8 @@ Sa-OAuth2 模块分为四种授权模式,解决不同场景下的授权需求
- [[ 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" />
......@@ -186,7 +188,8 @@ QQ交流群:837325627 [点击加入](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k
微信交流群:
![微信群](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,邀您加入群聊)
......
......@@ -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.4.0</solon.version>
<solon.version>2.5.3</solon.version>
<noear-redisx.version>1.4.8</noear-redisx.version>
<noear-snack3.version>3.2.72</noear-snack3.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>
......
......@@ -162,8 +162,8 @@
</script>
<!-- -->
<script src="./static/docsify-plugin.js"></script>
<script src="./static/is-star-plugin.js?v=3"></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 name = '<img style="width: 60px; height: 60px; vertical-align: middle;" src="logo.png" alt="logo" /> ';
......
......@@ -616,16 +616,22 @@
<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.png"
<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-deign.png"
msg="基于 Canvas 的开源版 创客贴 支持导出json,svg, image文件。">
</a>
<a href="https://dromara.org/zh/projects/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dromara.png"
......
......@@ -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}'
......
......@@ -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,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-Token:xxx`
### 三、服务内部调用鉴权
### 三、服务内部调用鉴权
有时候我们需要在一个服务调用另一个服务的接口,这也是需要添加`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());
}
}
```
......
......@@ -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:报错:NotLoginException:xxx
......@@ -623,6 +624,39 @@ So:从鉴权粒度的角度来看,需要针对一个模块鉴权的时候,
所以只能统一抛出-2,这个行为也和具体使用的 SaTokenDao 有关联,例如集成 sa-token-jwt 插件后,框架就能分辨出来是 token 过期了,抛出-3。
### Q:Sa-Token 是否提供类似 RefreshToken 的概念,与 AccessToken 相互配合刷新令牌鉴权。
关于长短 token,Sa-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)
......@@ -21,6 +21,7 @@ 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 |
......
......@@ -5,14 +5,14 @@
---
### 正式版本
v1.34.0 正式版,可上生产:
v1.35.0.RC 正式版,可上生产:
``` xml
<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.34.0</version>
<version>1.35.0.RC</version>
</dependency>
```
......
......@@ -74,13 +74,36 @@ var myDocsifyPlugin = function(hook, vm) {
// 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(123);
console.log('关闭广告');
// $('.top-ad-box').slideUp(); // 折叠收起
$(".top-ad-box").fadeOut(1000); // 淡出效果
layer.msg('一周内不再展现此信息')
localStorage.closeAdTime = new Date().getTime();
})
}
......
......@@ -3,9 +3,6 @@
// 声明 docsify 插件
var isStarPlugin = function(hook, vm) {
// 切换文档的次数,每隔固定次数检测一下
let changePage = -1;
// 钩子函数:解析之前执行
hook.beforeEach(function(content) {
return content;
......@@ -30,14 +27,14 @@ var isStarPlugin = function(hook, vm) {
// 应用参数
const client_id = '0cc618beb08db99bff50e500e38c2144d95ada9abb51c00c44592726ecd583f4';
const client_secret = '2574c2aac8ce2142e34752dc5957dddcb30bc68df5c61de64251a3a6b11a51e5';
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;
const allowDisparity = 1000 * 60 * 60 * 24 * 30 * 3;
// const allowDisparity = 1000 * 10;
......@@ -51,7 +48,7 @@ function isStarRepo(vm) {
// 判断是否在主域名下
if(location.host !== docDomain) {
console.log('非主域名,不检测...');
console.log('not domain, no check...');
return;
}
......@@ -73,7 +70,7 @@ function isStarRepo(vm) {
}
// 白名单路由不判断
const whiteList = ['/', '/more/link', '/more/demand-commit', '/more/join-group', '/more/sa-token-donate',
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 ...');
......@@ -110,7 +107,8 @@ function confirmStar() {
<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><b>本章节文档将在 star 后正常开放展示。</b></p>
<p style="color: green;">开源不易,希望您不吝支持,激励开源项目走的更加长远 😇😇😇</p>
</div>
`;
......@@ -118,7 +116,7 @@ function confirmStar() {
title: '提示',
btn: ['同意授权检测'],
// btn: ['同意授权检测', '暂时不要,我先看看文档'],
area: '450px',
area: '460px',
offset: '25%',
closeBtn: false
},
......@@ -129,6 +127,8 @@ function confirmStar() {
goAuth();
}
);
// 源码注释提示
const closeLayer =
`
<!--
......@@ -148,8 +148,7 @@ function goAuth() {
const authUrl = "https://gitee.com/oauth/authorize" +
"?client_id=" + client_id +
"&redirect_uri=" + redirect_uri +
"&response_type=code" +
"&scope=projects";
"&response_type=code";
location.href = authUrl;
}
......
......@@ -63,4 +63,5 @@ public class SaTokenConfigure {
gfuPSwZsnUhwgz08GTCH4wOgasWtc3odP4HLwXJ7NDGOximTvT4OlW19zeLH
```
!> **更改了 token 生成策略但是不生效?**<br> 把 Redis 中的旧数据清除掉再试试
......@@ -42,15 +42,36 @@
<optional>true</optional>
</dependency>
<!-- redisx + snack3 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>snack3</artifactId>
<artifactId>redisx</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>redisx</artifactId>
<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>
......
......@@ -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());
......
/*
* 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);
}
}
/*
* 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);
}
}
......@@ -23,39 +23,36 @@ import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.AppContext;
import org.noear.solon.core.bean.InitializingBean;
/**
* @author noear
* @since 2.0
*/
@Condition(onClass = SaOAuth2Manager.class)
@Configuration
public class SaOAuth2AutoConfigure {
/**
* 获取 OAuth2配置Bean
*/
@Bean
public SaOAuth2Config getConfig(@Inject(value = "${sa-token.oauth2}", required = false) SaOAuth2Config oAuth2Config) {
return oAuth2Config;
}
public class SaOAuth2AutoConfigure implements InitializingBean {
@Inject
private AppContext appContext;
/**
* 注入OAuth2配置Bean
*
* @param saOAuth2Config 配置对象
*/
@Bean
public void setSaOAuth2Config(@Inject(required = false) SaOAuth2Config saOAuth2Config) {
SaOAuth2Manager.setConfig(saOAuth2Config);
@Override
public void afterInjection() throws Throwable {
appContext.subBeansOfType(SaOAuth2Template.class, bean -> {
SaOAuth2Util.saOAuth2Template = bean;
});
appContext.subBeansOfType(SaOAuth2Config.class, bean -> {
SaOAuth2Manager.setConfig(bean);
});
}
/**
* 注入代码模板Bean
*
* @param saOAuth2Template 代码模板Bean
* 获取 OAuth2配置Bean
*/
@Bean
public void setSaOAuth2Interface(@Inject(required = false) SaOAuth2Template saOAuth2Template) {
SaOAuth2Util.saOAuth2Template = saOAuth2Template;
public SaOAuth2Config getConfig(@Inject(value = "${sa-token.oauth2}", required = false) SaOAuth2Config oAuth2Config) {
return oAuth2Config;
}
}
}
\ No newline at end of file
......@@ -24,14 +24,32 @@ import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.AppContext;
import org.noear.solon.core.bean.InitializingBean;
/**
* @author noear
* @since 2.0
*/
@Condition(onClass = SaSsoManager.class)
@Configuration
public class SaSsoAutoConfigure {
public class SaSsoAutoConfigure implements InitializingBean {
@Inject
private AppContext appContext;
@Override
public void afterInjection() throws Throwable {
appContext.subBeansOfType(SaSsoTemplate.class, bean->{
SaSsoUtil.ssoTemplate = bean;
SaSsoProcessor.instance.ssoTemplate = bean;
});
appContext.subBeansOfType(SaSsoConfig.class, bean->{
SaSsoManager.setConfig(bean);
});
}
/**
* 获取 SSO 配置Bean
* */
......@@ -39,25 +57,4 @@ public class SaSsoAutoConfigure {
public SaSsoConfig getConfig(@Inject(value = "${sa-token.sso}",required = false) SaSsoConfig ssoConfig) {
return ssoConfig;
}
/**
* 注入 Sa-Token-SSO 配置Bean
*
* @param saSsoConfig 配置对象
*/
@Bean
public void setSaSsoConfig(@Inject(required = false) SaSsoConfig saSsoConfig) {
SaSsoManager.setConfig(saSsoConfig);
}
/**
* 注入 Sa-Token-SSO 单点登录模块 Bean
*
* @param ssoTemplate saSsoTemplate对象
*/
@Bean
public void setSaSsoTemplate(@Inject(required = false) SaSsoTemplate ssoTemplate) {
SaSsoUtil.ssoTemplate = ssoTemplate;
SaSsoProcessor.instance.ssoTemplate = ssoTemplate;
}
}
}
\ No newline at end of file