From c1e7dce1dc7ba5f1ec410c39b259595946fc9e59 Mon Sep 17 00:00:00 2001 From: noear Date: Tue, 10 May 2022 13:47:49 +0800 Subject: [PATCH 001/144] =?UTF-8?q?sa-token-dao-redisx=EF=BC=9A=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-plugin/sa-token-dao-redisx/README.md | 33 +++++++++++++++++++ sa-token-plugin/sa-token-dao-redisx/pom.xml | 1 + 2 files changed, 34 insertions(+) create mode 100644 sa-token-plugin/sa-token-dao-redisx/README.md diff --git a/sa-token-plugin/sa-token-dao-redisx/README.md b/sa-token-plugin/sa-token-dao-redisx/README.md new file mode 100644 index 00000000..3a73e3f2 --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redisx/README.md @@ -0,0 +1,33 @@ + +### 使用示例 + +#### 1.配置 + +```yaml +sa-token-dao: #名字可以随意取 + redis: + server: "localhost:6379" + password: 123456 + db: 1 +``` + +#### 2.代码 + +**注入风格** + +```java +@Configuration +public class Config { + @Bean + public SaTokenDao saTokenDaoInit(@Inject("${sa-token-dao.redis}") SaTokenDaoOfRedis saTokenDao) { + return saTokenDao; + } +} +``` + +**手动风格** + +```java +SaTokenDaoOfRedis saTokenDao = new SaTokenDaoOfRedis(props); +SaManager.setSaTokenDao(saTokenDao); +``` \ No newline at end of file diff --git a/sa-token-plugin/sa-token-dao-redisx/pom.xml b/sa-token-plugin/sa-token-dao-redisx/pom.xml index cd16dd7a..62bdb4fb 100644 --- a/sa-token-plugin/sa-token-dao-redisx/pom.xml +++ b/sa-token-plugin/sa-token-dao-redisx/pom.xml @@ -34,6 +34,7 @@ org.noear solon-test 1.7.5 + test From 46cda3e0e87a4bce75f3e88b5095ee54ec3976fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E6=95=B2=E4=BB=A3=E7=A0=81=E7=9A=84=E5=B0=8F?= =?UTF-8?q?=E5=BA=86?= <1578442339@qq.com> Date: Tue, 10 May 2022 07:10:01 +0000 Subject: [PATCH 002/144] update sa-token-doc/doc/more/link.md. --- sa-token-doc/doc/more/link.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index 0d202d0b..f9e5dd18 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -61,8 +61,12 @@ - [[ Huanxing-mall ]](https://gitee.com/lijiaxing_boy/huanxing-mall):HuanXing 商城基于SpringCloud 2021 & Alibaba + Sa-token,前端基于 Vue3 +Element plus 的微服务商城 - [[ SpringMvc+Sa-Token ]](https://gitee.com/SRD_01/spring-mvc-sa-token): Jsp+SpringMVC+SSO+Sa-Token+Redis | Spring MVC 集成 SaToken Demo 项目 + + +- [[ 自定义快速搭建平台 ]](https://gitee.com/CodeLiQing/custom-quick-build-platform): MybatisPlus+SpringMVC+SSO+Sa-Token+Redis | 基于springboot+as-token+neety+代码生产器(vm实现)| 以及前端vue的element-ui 和大屏框架DataV
+ --- ### 推荐项目: From 6833c4d86663cf6e7e11789a4b28dcebb676f11c Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 11 May 2022 00:01:14 +0800 Subject: [PATCH 003/144] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=87=E7=94=A8?= =?UTF-8?q?=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/index-backup.html | 208 +++++++++++++++++++++++++++++ sa-token-doc/doc/index.html | 9 +- 2 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 sa-token-doc/doc/index-backup.html diff --git a/sa-token-doc/doc/index-backup.html b/sa-token-doc/doc/index-backup.html new file mode 100644 index 00000000..a47813a2 --- /dev/null +++ b/sa-token-doc/doc/index-backup.html @@ -0,0 +1,208 @@ + + + + + Sa-Token + + + + + + + + + + +
+ + +
+ + +
+
加载中...
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + diff --git a/sa-token-doc/doc/index.html b/sa-token-doc/doc/index.html index aa11b204..d93dbc82 100644 --- a/sa-token-doc/doc/index.html +++ b/sa-token-doc/doc/index.html @@ -160,13 +160,20 @@ - + + + - + @@ -168,7 +168,7 @@ - + diff --git a/sa-token-doc/doc/index.html b/sa-token-doc/doc/index.html index aec8994e..4281a962 100644 --- a/sa-token-doc/doc/index.html +++ b/sa-token-doc/doc/index.html @@ -153,7 +153,7 @@ - + diff --git a/sa-token-doc/doc/lib/prism-java.min.js b/sa-token-doc/doc/lib/prism-java.min.js new file mode 100644 index 00000000..079c8d4e --- /dev/null +++ b/sa-token-doc/doc/lib/prism-java.min.js @@ -0,0 +1 @@ +!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|null|open|opens|package|private|protected|provides|public|record|requires|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,a=/\b[A-Z](?:\w*[a-z]\w*)?\b/;e.languages.java=e.languages.extend("clike",{"class-name":[a,/\b[A-Z]\w*(?=\s+\w+\s*[;,=())])/],keyword:t,function:[e.languages.clike.function,{pattern:/(\:\:)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x[\da-f_]*\.?[\da-f_p+-]+\b|(?:\b\d[\d_]*\.?[\d_]*|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"}}),e.languages.insertBefore("java","class-name",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0},namespace:{pattern:/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)[a-z]\w*(?:\.[a-z]\w*)+/,lookbehind:!0,inside:{punctuation:/\./}},generics:{pattern:/<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}}})}(Prism); \ No newline at end of file diff --git a/sa-token-doc/doc/sso/sso-type3.md b/sa-token-doc/doc/sso/sso-type3.md index edb70b9d..6fdf31ae 100644 --- a/sa-token-doc/doc/sso/sso-type3.md +++ b/sa-token-doc/doc/sso/sso-type3.md @@ -106,19 +106,60 @@ public Object myinfo() { } ``` +#### 3.3、访问测试 访问测试:[http://sa-sso-client1.com:9001/sso/myinfo](http://sa-sso-client1.com:9001/sso/myinfo) -#### 3.3、疑问 + +### 4、自定义接口通信 群里有小伙伴提问:`SaSsoUtil.getUserinfo` 提供的参数太少,只有一个 loginId,无法满足业务需求怎么办? 答:SaSsoUtil.getUserinfo只是为了避免你在项目中硬编码认证中心 url 而提供的简易封装,如果这个API无法满足你的业务需求, 你完全可以在 Server 端自定义一些接口然后从 Client 端使用 http 工具调用即可。 +以下是一个简单的示例: + +#### 4.1、先在 sso-server 端自定义一个接口 +``` java +// 获取指定用户的关注列表 +@RequestMapping("/sso/getFollowList") +public Object ssoRequest(Long loginId) { + + // 校验签名,签名不通过直接抛出异常 + SaSsoUtil.checkSign(SaHolder.getRequest()); + + // 查询数据 (此处仅做模拟) + List list = Arrays.asList(10041, 10042, 10043, 10044); + + // 返回 + return list; +} +``` + + +#### 4.2、然后在 sso-client 端调用这个接口 +``` java +// 查询我的账号信息 +@RequestMapping("/sso/myFollowList") +public Object myFollowList() { + // 组织url,加上签名参数 + String url = SaSsoUtil.addSignParams("http://sa-sso-server.com:9000/sso/getFollowList", StpUtil.getLoginId()); + + // 调用,并返回 SaResult 结果 + SaResult res = SaSsoUtil.request(url); + + // 返回给前端 + return res; +} +``` + +#### 4.3、访问测试 +访问测试:[http://sa-sso-client1.com:9001/sso/myFollowList](http://sa-sso-client1.com:9001/sso/myFollowList) -### 4、无刷单点注销 + +### 5、无刷单点注销 有了单点登录就必然要有单点注销,网上给出的大多数解决方案是将注销请求重定向至SSO-Server中心,逐个通知Client端下线 @@ -137,7 +178,7 @@ public Object myinfo() { 这些逻辑 Sa-Token 内部已经封装完毕,你只需按照文档增加以下配置即可: -#### 4.1、SSO-Client 端新增配置 +#### 5.1、SSO-Client 端新增配置 在 `application.yml` 增加配置:`API调用秘钥` 和 `单点注销接口URL`。 ``` yml @@ -153,7 +194,7 @@ sa-token: 注意 secretkey 秘钥需要与SSO认证中心的一致 -#### 4.2 启动测试 +#### 5.2、启动测试 重启项目,访问测试:[http://sa-sso-client1.com:9001/](http://sa-sso-client1.com:9001/), 我们主要的测试点在于 `单点注销`,正常登录即可。 @@ -167,16 +208,16 @@ sa-token: PS:这里我们为了方便演示,使用的是超链接跳页面的形式,正式项目中使用 Ajax 调用接口即可做到无刷单点登录退出。 -例如,我们使用 [APIPost接口测试工具](https://www.apipost.cn/) 可以做到同样的效果: +例如,我们使用 [Apifox 接口测试工具](https://www.apifox.cn/) 可以做到同样的效果: -![sso-slo-apipost.png](https://oss.dev33.cn/sa-token/doc/sso/sso-slo-apipost.png 's-w-sh') +![sso-slo-apifox.png](https://oss.dev33.cn/sa-token/doc/sso/sso-slo-apifox.png 's-w-sh') 测试完毕! -### 4、后记 +### 6、后记 当我们熟读三种模式的单点登录之后,其实不难发现:所谓单点登录,其本质就是多个系统之间的会话共享。 当我们理解这一点之后,三种模式的工作原理也浮出水面: From c1ef574b74ccabf3b7c5591ab1fd7464955b008e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=94=E6=98=8E?= <2393584716@qq.com> Date: Wed, 18 May 2022 14:53:48 +0000 Subject: [PATCH 006/144] update sa-token-doc/doc/sso/sso-custom-api.md. --- sa-token-doc/doc/sso/sso-custom-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/sso/sso-custom-api.md b/sa-token-doc/doc/sso/sso-custom-api.md index 184f71bb..30588d84 100644 --- a/sa-token-doc/doc/sso/sso-custom-api.md +++ b/sa-token-doc/doc/sso/sso-custom-api.md @@ -25,7 +25,7 @@ public class SsoServerController { 这种写法集成简单但却不够灵活。例如认证中心地址只能是:`http://{host}:{port}/sso/auth`,如果我们想要自定义其API地址,应该怎么做呢? -我们可以打开SSO模块相关源码,有关 API 的设计都定义在:[SaSsoConsts.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java) +我们可以打开SSO模块相关源码,有关 API 的设计都定义在:[SaSsoConsts.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java) 中,这些值从架构设计上来讲属于常量却并未使用 `final` 修饰,目的就是为了方便我们对其二次修改。 例如,我们可以在 Main 方法启动类或者 SSO 配置方法中修改变量值: From 6cd83c3839def15f738e257e493c6d62fdc4f230 Mon Sep 17 00:00:00 2001 From: xiwa Date: Thu, 19 May 2022 11:08:08 +0000 Subject: [PATCH 007/144] =?UTF-8?q?update=20sa-token-doc/doc/more/link.md.?= =?UTF-8?q?=20=E7=94=B3=E8=AF=B7=E6=B7=BB=E5=8A=A0iot-kit=20=E5=BC=80?= =?UTF-8?q?=E6=BA=90=E7=94=9F=E6=80=81=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/link.md | 1 + 1 file changed, 1 insertion(+) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index f9e5dd18..7b020f57 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -15,6 +15,7 @@ ### 使用 Sa-Token 的开源项目: +- [[ iot-kit ]](https://gitee.com/iotkit-open-source/iotkit-parent):一个轻量级低门槛的物联网平台,包含了多协议设备接入、规则引擎、第三方平台接入、智能家居小程序等模块的项目,基于SpringBoot架构并集成了Sa-Token的OAuth2认证。 - [[ Sa-Plus ]](https://gitee.com/click33/sa-plus):一个基于 SpringBoot 架构的快速开发框架,内置代码生成器 From ba72774050c9dd67c46db879b2792ddec7f0274c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=94=E6=98=8E?= <2393584716@qq.com> Date: Sun, 22 May 2022 22:24:43 +0000 Subject: [PATCH 008/144] update README.md. --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index be65b772..8b7e6ad1 100644 --- a/README.md +++ b/README.md @@ -137,13 +137,10 @@ Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) ## 交流群 -QQ交流群:1群:1002350610 (已满) 、 -2群:614714762 [点击加入](https://jq.qq.com/?_wv=1027&k=b759RZrL) +QQ交流群:496757342 [点击加入](https://jq.qq.com/?_wv=1027&k=ceibbMFr) 微信交流群: - - ![微信群](https://dev33-test.oss-cn-beijing.aliyuncs.com/sa-token/i-wx-qr.png ':size=230') (扫码添加微信,备注:sa-token,邀您加入群聊) From 3f6a753cdd6b69c3d92eb13c3c14ddb39b5b2b6a Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 23 May 2022 06:33:15 +0800 Subject: [PATCH 009/144] =?UTF-8?q?=E6=9B=B4=E6=8D=A2qq=E7=BE=A4=E9=93=BE?= =?UTF-8?q?=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/README.md | 3 +-- sa-token-doc/doc/index-backup.html | 2 +- sa-token-doc/doc/index.html | 2 +- sa-token-doc/doc/lib/docsify-copy-code.min.js | 9 +++++++++ sa-token-doc/doc/lib/docsify-plugin.js | 2 +- sa-token-doc/doc/lib/docsify-tabs.min.js | 2 +- sa-token-doc/doc/sso/sso-custom-api.md | 4 ++-- sa-token-doc/doc/sso/sso-custom-login.md | 2 +- sa-token-doc/doc/sso/sso-server.md | 8 ++++---- sa-token-doc/doc/sso/sso-type1.md | 4 ++-- sa-token-doc/doc/sso/sso-type3.md | 4 ++-- sa-token-doc/doc/up/global-filter.md | 11 +++++++++++ sa-token-doc/index.html | 6 +++--- 13 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 sa-token-doc/doc/lib/docsify-copy-code.min.js diff --git a/sa-token-doc/doc/README.md b/sa-token-doc/doc/README.md index b9225ef2..d54abb2f 100644 --- a/sa-token-doc/doc/README.md +++ b/sa-token-doc/doc/README.md @@ -134,8 +134,7 @@ StpUtil.switchTo(10044); // 将当前会话身份临时切换为其它账号 ## 交流群 -QQ交流群:1群:1002350610 (已满) 、 -2群:614714762 [点击加入](https://jq.qq.com/?_wv=1027&k=b759RZrL) +QQ交流群:496757342 [点击加入](https://jq.qq.com/?_wv=1027&k=WNggbsFe) 微信交流群: diff --git a/sa-token-doc/doc/index-backup.html b/sa-token-doc/doc/index-backup.html index a5c27047..041c7074 100644 --- a/sa-token-doc/doc/index-backup.html +++ b/sa-token-doc/doc/index-backup.html @@ -151,7 +151,7 @@ } - + diff --git a/sa-token-doc/doc/index.html b/sa-token-doc/doc/index.html index 4281a962..1b299916 100644 --- a/sa-token-doc/doc/index.html +++ b/sa-token-doc/doc/index.html @@ -152,7 +152,7 @@ } - + diff --git a/sa-token-doc/doc/lib/docsify-copy-code.min.js b/sa-token-doc/doc/lib/docsify-copy-code.min.js new file mode 100644 index 00000000..d48cab49 --- /dev/null +++ b/sa-token-doc/doc/lib/docsify-copy-code.min.js @@ -0,0 +1,9 @@ +/*! + * docsify-copy-code + * v2.1.0 + * https://github.com/jperasmus/docsify-copy-code + * (c) 2017-2019 JP Erasmus + * MIT license + */ +!function(){"use strict";function r(o){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o})(o)}!function(o,e){void 0===e&&(e={});var t=e.insertAt;if(o&&"undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],c=document.createElement("style");c.type="text/css","top"===t&&n.firstChild?n.insertBefore(c,n.firstChild):n.appendChild(c),c.styleSheet?c.styleSheet.cssText=o:c.appendChild(document.createTextNode(o))}}(".docsify-copy-code-button,.docsify-copy-code-button span{cursor:pointer;transition:all .25s ease}.docsify-copy-code-button{position:absolute;z-index:1;top:0;right:0;overflow:visible;padding:.65em .8em;border:0;border-radius:0;outline:0;font-size:1em;background:grey;background:var(--theme-color,grey);color:#fff;opacity:0}.docsify-copy-code-button span{border-radius:3px;background:inherit;pointer-events:none}.docsify-copy-code-button .error,.docsify-copy-code-button .success{position:absolute;z-index:-100;top:50%;left:0;padding:.5em .65em;font-size:.825em;opacity:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.docsify-copy-code-button.error .error,.docsify-copy-code-button.success .success{opacity:1;-webkit-transform:translate(-115%,-50%);transform:translate(-115%,-50%)}.docsify-copy-code-button:focus,pre:hover .docsify-copy-code-button{opacity:1}"),document.querySelector('link[href*="docsify-copy-code"]')&&console.warn("[Deprecation] Link to external docsify-copy-code stylesheet is no longer necessary."),window.DocsifyCopyCodePlugin={init:function(){return function(o,e){o.ready(function(){console.warn("[Deprecation] Manually initializing docsify-copy-code using window.DocsifyCopyCodePlugin.init() is no longer necessary.")})}}},window.$docsify=window.$docsify||{},window.$docsify.plugins=[function(o,s){o.doneEach(function(){var o=Array.apply(null,document.querySelectorAll("pre[data-lang]")),c={buttonText:"Copy to clipboard",errorText:"Error",successText:"Copied"};s.config.copyCode&&Object.keys(c).forEach(function(t){var n=s.config.copyCode[t];"string"==typeof n?c[t]=n:"object"===r(n)&&Object.keys(n).some(function(o){var e=-1',''.concat(c.buttonText,""),''.concat(c.errorText,""),''.concat(c.successText,""),""].join("");o.forEach(function(o){o.insertAdjacentHTML("beforeend",e)})}),o.mounted(function(){document.querySelector(".content").addEventListener("click",function(o){if(o.target.classList.contains("docsify-copy-code-button")){var e="BUTTON"===o.target.tagName?o.target:o.target.parentNode,t=document.createRange(),n=e.parentNode.querySelector("code"),c=window.getSelection();t.selectNode(n),c.removeAllRanges(),c.addRange(t);try{document.execCommand("copy")&&(e.classList.add("success"),setTimeout(function(){e.classList.remove("success")},1e3))}catch(o){console.error("docsify-copy-code: ".concat(o)),e.classList.add("error"),setTimeout(function(){e.classList.remove("error")},1e3)}"function"==typeof(c=window.getSelection()).removeRange?c.removeRange(t):"function"==typeof c.removeAllRanges&&c.removeAllRanges()}})})}].concat(window.$docsify.plugins||[])}(); +//# sourceMappingURL2=docsify-copy-code.min.js.map \ No newline at end of file diff --git a/sa-token-doc/doc/lib/docsify-plugin.js b/sa-token-doc/doc/lib/docsify-plugin.js index 9a386f66..8e4c0e8a 100644 --- a/sa-token-doc/doc/lib/docsify-plugin.js +++ b/sa-token-doc/doc/lib/docsify-plugin.js @@ -27,7 +27,7 @@ var myDocsifyPlugin = function(hook, vm) { '' ].join(''); return html + footer; diff --git a/sa-token-doc/doc/lib/docsify-tabs.min.js b/sa-token-doc/doc/lib/docsify-tabs.min.js index ee3e2f07..8c9328ac 100644 --- a/sa-token-doc/doc/lib/docsify-tabs.min.js +++ b/sa-token-doc/doc/lib/docsify-tabs.min.js @@ -6,4 +6,4 @@ * MIT license */ !function(){"use strict";!function(t,a){void 0===a&&(a={});var o=a.insertAt;if(t&&"undefined"!=typeof document){var c=document.head||document.getElementsByTagName("head")[0],e=document.createElement("style");e.type="text/css","top"===o&&c.firstChild?c.insertBefore(e,c.firstChild):c.appendChild(e),e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t))}}(':root{--docsifytabs-border-color:#ededed;--docsifytabs-border-px:1px;--docsifytabs-margin:1.5em 0;--docsifytabs-tab-background:#f8f8f8;--docsifytabs-tab-background--active:var(--docsifytabs-content-background);--docsifytabs-tab-color:#999;--docsifytabs-tab-color--active:inherit;--docsifytabs-tab-highlight-px:3px;--docsifytabs-tab-highlight-color:var(--theme-color,currentColor);--docsifytabs-tab-padding:0.6em 1em;--docsifytabs-content-background:inherit;--docsifytabs-content-padding:1.5rem}.docsify-tabs:before,.docsify-tabs__tab{z-index:1}.docsify-tabs__tab--active,.docsify-tabs__tab:focus{z-index:2}.docsify-tabs{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;position:relative}.docsify-tabs:before{content:"";-ms-flex-order:0;order:0;-ms-flex:1;flex:1 1}.docsify-tabs__tab{-ms-flex-order:-1;order:-1;position:relative;margin:0;font-size:inherit;appearance:none}.docsify-tabs__content{visibility:hidden;position:absolute;overflow:hidden;height:0;width:100%}.docsify-tabs__content :first-child{margin-top:0}.docsify-tabs__content :first-child~:last-child,.docsify-tabs__content :last-child{margin-bottom:0}.docsify-tabs__tab--active+.docsify-tabs__content{visibility:visible;position:relative;overflow:auto;height:auto}[class*=docsify-tabs--]{margin:1.5em 0;margin:var(--docsifytabs-margin)}[class*=docsify-tabs--] .docsify-tabs__tab{padding:.6em 1em;padding:var(--docsifytabs-tab-padding);background:#f8f8f8;background:var(--docsifytabs-tab-background);color:#999;color:var(--docsifytabs-tab-color)}[class*=docsify-tabs--] .docsify-tabs__tab--active{background:inherit;background:var(--docsifytabs-tab-background--active);color:inherit;color:var(--docsifytabs-tab-color--active)}[class*=docsify-tabs--] .docsify-tabs__content{padding:1.5rem;padding:var(--docsifytabs-content-padding);background:inherit;background:var(--docsifytabs-content-background)}.docsify-tabs--classic .docsify-tabs__content,.docsify-tabs--classic .docsify-tabs__tab,.docsify-tabs--classic:before{border-width:1px;border-color:#ededed;border:var(--docsifytabs-border-px) solid var(--docsifytabs-border-color)}.docsify-tabs--classic:before{margin-right:1px;margin-right:var(--docsifytabs-border-px);border-top-width:0;border-left-width:0;border-right-width:0}.docsify-tabs--classic .docsify-tabs__tab:first-of-type{border-top-left-radius:var(--docsifytabs-border-radius-px)}.docsify-tabs--classic .docsify-tabs__tab:last-of-type{border-top-right-radius:var(--docsifytabs-border-radius-px)}.docsify-tabs--classic .docsify-tabs__tab~.docsify-tabs__tab{margin-left:-1px;margin-left:calc(0px - var(--docsifytabs-border-px))}.docsify-tabs--classic .docsify-tabs__tab--active{border-bottom-width:0;box-shadow:inset 0 3px 0 0 var(--theme-color,currentColor);box-shadow:inset 0 var(--docsifytabs-tab-highlight-px) 0 0 var(--docsifytabs-tab-highlight-color)}.docsify-tabs--classic .docsify-tabs__content{margin-top:-1px;margin-top:calc(0px - var(--docsifytabs-border-px));border-top:0;border-radius:0;border-radius:0 var(--docsifytabs-border-radius-px) var(--docsifytabs-border-radius-px) var(--docsifytabs-border-radius-px)}.docsify-tabs--material .docsify-tabs__tab{margin-bottom:2px;margin-bottom:calc(var(--docsifytabs-tab-highlight-px) - var(--docsifytabs-border-px));background:transparent;border:0}.docsify-tabs--material .docsify-tabs__tab--active{box-shadow:0 3px 0 0 var(--theme-color,currentColor);box-shadow:0 var(--docsifytabs-tab-highlight-px) 0 0 var(--docsifytabs-tab-highlight-color);background:transparent}.docsify-tabs--material .docsify-tabs__content{border-width:1px 0;border-color:#ededed;border-left:0 solid var(--docsifytabs-border-color);border-bottom:var(--docsifytabs-border-px) solid var(--docsifytabs-border-color);border-right:0 solid var(--docsifytabs-border-color);border-top:var(--docsifytabs-border-px) solid var(--docsifytabs-border-color)}',{insertAt:"top"});var u="tabs:replace",y={tabsContainer:"content",tabBlock:"docsify-tabs",tabButton:"docsify-tabs__tab",tabButtonActive:"docsify-tabs__tab--active",tabContent:"docsify-tabs__content"},p={codeMarkup:/(```[\s\S]*?```)/gm,commentReplaceMarkup:new RegExp("\x3c!-- ".concat(u," (.*) --\x3e")),tabBlockMarkup:/[\r\n]*(\s*)()[\r\n]+([\s|\S]*?)[\r\n\s]+()/m,tabCommentMarkup:/[\r\n]*(\s*)[\r\n]+([\s\S]*?)[\r\n]*\s*(?=)/m},m={persist:!0,sync:!0,theme:"classic",tabComments:!0,tabHeadings:!0};function g(t,a){var o=1 --\x3e'),a="\n".concat(s,"\x3c!-- ").concat(u," --\x3e");for(var i=function(){var t=(f[2]||"[Tab]").trim(),a=(f[3]||"").trim();o=o.replace(f[0],function(){return["\n".concat(s,"\x3c!-- ").concat(u,' --\x3e"),"\n".concat(s,"\x3c!-- ").concat(u,'
--\x3e'),"\n\n".concat(s).concat(a),"\n\n".concat(s,"\x3c!-- ").concat(u,"
--\x3e")].join("")})};null!==(f=(m.tabComments?p.tabCommentMarkup.exec(o):null)||(m.tabHeadings?p.tabHeadingMarkup.exec(o):null));)i()}o=(o=o.replace(r,function(){return t})).replace(n,function(){return a}),d=d.replace(b[0],function(){return o})};null!==(b=p.tabBlockMarkup.exec(d));)a();return t.forEach(function(t,a){d=d.replace(t,function(){return o[a]})}),d}(t)),t}),t.afterEach(function(t,a){o&&(t=function(o){for(var c,t=function(){var t=c[0],a=c[1]||"";o=o.replace(t,function(){return a})};null!==(c=p.commentReplaceMarkup.exec(o));)t();return o}(t)),a(t)}),t.doneEach(function(){var t,a,c,e;o&&(t=document.querySelector(".".concat(y.tabsContainer)),a=t?Array.apply(null,t.querySelectorAll(".".concat(y.tabBlock))):[],c=JSON.parse(sessionStorage.getItem(window.location.href))||{},e=JSON.parse(sessionStorage.getItem("*"))||[],s(),a.forEach(function(a,t){var o=a.querySelector(".".concat(y.tabButtonActive));o||(m.sync&&e.length&&(o=e.map(function(t){return a.querySelector(".".concat(y.tabButton,'[data-tab="').concat(t,'"]'))}).filter(function(t){return t})[0]),!o&&m.persist&&(o=a.querySelector(".".concat(y.tabButton,'[data-tab="').concat(c[t],'"]'))),(o=o||a.querySelector(".".concat(y.tabButton)))&&o.classList.add(y.tabButtonActive))}))}),t.mounted(function(){var t=document.querySelector(".".concat(y.tabsContainer));t&&t.addEventListener("click",function(t){g(t.target)}),window.addEventListener("hashchange",s,!1)})},window.$docsify.plugins||[])))}(); -//# sourceMappingURL=docsify-tabs.min.js.map \ No newline at end of file +//# sourceMappingURL2=docsify-tabs.min.js.map \ No newline at end of file diff --git a/sa-token-doc/doc/sso/sso-custom-api.md b/sa-token-doc/doc/sso/sso-custom-api.md index 184f71bb..c5649fe6 100644 --- a/sa-token-doc/doc/sso/sso-custom-api.md +++ b/sa-token-doc/doc/sso/sso-custom-api.md @@ -32,13 +32,13 @@ public class SsoServerController { ``` java // 配置SSO相关参数 @Autowired -private void configSso(SaTokenConfig cfg) { +private void configSso(SaSsoConfig sso) { // 自定义API地址 SaSsoConsts.Api.ssoAuth = "/sso/auth2"; // ... // SSO 相关配置 - cfg.sso.setXxx ... ; + sso.setXxx ... ; } ``` diff --git a/sa-token-doc/doc/sso/sso-custom-login.md b/sa-token-doc/doc/sso/sso-custom-login.md index 5905c488..5d103dd3 100644 --- a/sa-token-doc/doc/sso/sso-custom-login.md +++ b/sa-token-doc/doc/sso/sso-custom-login.md @@ -81,7 +81,7 @@ if(res.code == 401) { ``` java // 配置:未登录时返回的View -cfg.sso.setNotLoginView(() -> { +sso.setNotLoginView(() -> { return new ModelAndView("xxx.html"); }) ``` diff --git a/sa-token-doc/doc/sso/sso-server.md b/sa-token-doc/doc/sso/sso-server.md index c7cb77fe..b0a91c64 100644 --- a/sa-token-doc/doc/sso/sso-server.md +++ b/sa-token-doc/doc/sso/sso-server.md @@ -79,9 +79,9 @@ public class SsoServerController { * 配置SSO相关参数 */ @Autowired - private void configSso(SaTokenConfig cfg) { + private void configSso(SaSsoConfig sso) { // 配置:未登录时返回的View - cfg.sso.setNotLoginView(() -> { + sso.setNotLoginView(() -> { String msg = "当前会话在SSO-Server端尚未登录,请先访问" + " doLogin登录 " + "进行登录之后,刷新页面开始授权"; @@ -89,7 +89,7 @@ public class SsoServerController { }); // 配置:登录处理函数 - cfg.sso.setDoLoginHandle((name, pwd) -> { + sso.setDoLoginHandle((name, pwd) -> { // 此处仅做模拟登录,真实环境应该查询数据进行登录 if("sa".equals(name) && "123456".equals(pwd)) { StpUtil.login(10001); @@ -99,7 +99,7 @@ public class SsoServerController { }); // 配置 Http 请求处理器 (在模式三的单点注销功能下用到,如不需要可以注释掉) - cfg.sso.setSendHttp(url -> { + sso.setSendHttp(url -> { try { // 发起 http 请求 System.out.println("发起请求:" + url); diff --git a/sa-token-doc/doc/sso/sso-type1.md b/sa-token-doc/doc/sso/sso-type1.md index 5f860191..b70348d8 100644 --- a/sa-token-doc/doc/sso/sso-type1.md +++ b/sa-token-doc/doc/sso/sso-type1.md @@ -109,8 +109,8 @@ public class SsoClientController { // SSO-Client端:首页 @RequestMapping("/") public String index() { - String authUrl = SaManager.getConfig().getSso().getAuthUrl(); - String solUrl = SaManager.getConfig().getSso().getSloUrl(); + String authUrl = SaSsoManager.getConfig().getAuthUrl(); + String solUrl = SaSsoManager.getConfig().getSloUrl(); String str = "

Sa-Token SSO-Client 应用端

" + "

当前会话是否登录:" + StpUtil.isLogin() + "

" + "

登录 " + diff --git a/sa-token-doc/doc/sso/sso-type3.md b/sa-token-doc/doc/sso/sso-type3.md index 6fdf31ae..4ebf827b 100644 --- a/sa-token-doc/doc/sso/sso-type3.md +++ b/sa-token-doc/doc/sso/sso-type3.md @@ -36,11 +36,11 @@ ``` java // 配置SSO相关参数 @Autowired -private void configSso(SaTokenConfig cfg) { +private void configSso(SaSsoConfig sso) { // ... 其他代码 // 配置 Http 请求处理器 - cfg.sso.setSendHttp(url -> { + sso.setSendHttp(url -> { System.out.println("发起请求:" + url); return OkHttps.sync(url).get().getBody().toString(); }); diff --git a/sa-token-doc/doc/up/global-filter.md b/sa-token-doc/doc/up/global-filter.md index 1b5b6d6b..35da50bb 100644 --- a/sa-token-doc/doc/up/global-filter.md +++ b/sa-token-doc/doc/up/global-filter.md @@ -79,6 +79,17 @@ public class SaTokenConfigure { - 由于过滤器中抛出的异常不进入全局异常处理,所以你必须提供`[异常处理函数]`来处理`[认证函数]`里抛出的异常 - 在`[异常处理函数]`里的返回值,将作为字符串输出到前端,如果需要定制化返回数据,请注意其中的格式转换 +改写 `setError` 函数的响应格式示例: +``` java +.setError(e -> { + // 设置响应头 + SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8"); + // 使用封装的 JSON 工具类转换数据格式 + return JSONUtil.toJsonStr( SaResult.error(e.getMessage()) ); +}) +``` +JSON 工具类可参考:[Hutool-Json](https://hutool.cn/docs/#/json/JSONUtil) + ### 在 WebFlux 中注册过滤器 `Spring WebFlux`中不提供拦截器机制,因此若你的项目需要路由鉴权功能,过滤器是你唯一的选择,在`Spring WebFlux`注册过滤器的流程与上述流程几乎完全一致, diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 62caab5f..5ec5726a 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -87,8 +87,8 @@

- -

QQ交流群: 614714762 点击加入

+ +

QQ交流群: 496757342 点击加入

@@ -318,7 +318,7 @@

联系我们

From e0b3b63e1d8ab6b3cbb53b9a8374fdff3cbca41a Mon Sep 17 00:00:00 2001 From: noear Date: Tue, 24 May 2022 12:36:11 +0800 Subject: [PATCH 010/144] =?UTF-8?q?sa-token-solon-plugin=EF=BC=9A=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=20solon=20=E4=B8=BA=201.8.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-demo/sa-token-demo-solon/pom.xml | 2 +- .../sa-token-solon-plugin/pom.xml | 2 +- .../cn/dev33/satoken/solon/XPluginImp.java | 73 +++++++++---------- 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/sa-token-demo/sa-token-demo-solon/pom.xml b/sa-token-demo/sa-token-demo-solon/pom.xml index 53b55bbe..2a73e17c 100644 --- a/sa-token-demo/sa-token-demo-solon/pom.xml +++ b/sa-token-demo/sa-token-demo-solon/pom.xml @@ -18,7 +18,7 @@ org.noear solon-web - 1.7.5 + 1.8.0 diff --git a/sa-token-starter/sa-token-solon-plugin/pom.xml b/sa-token-starter/sa-token-solon-plugin/pom.xml index 159d28fb..0b8b1144 100644 --- a/sa-token-starter/sa-token-solon-plugin/pom.xml +++ b/sa-token-starter/sa-token-solon-plugin/pom.xml @@ -20,7 +20,7 @@ org.noear solon - 1.7.5 + 1.8.0 diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java index aff074e5..65823601 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java @@ -1,16 +1,11 @@ package cn.dev33.satoken.solon; import org.noear.solon.Solon; -import org.noear.solon.SolonApp; -import org.noear.solon.core.Aop; +import org.noear.solon.core.AopContext; import org.noear.solon.core.Plugin; import cn.dev33.satoken.SaManager; -import cn.dev33.satoken.annotation.SaCheckBasic; -import cn.dev33.satoken.annotation.SaCheckLogin; -import cn.dev33.satoken.annotation.SaCheckPermission; -import cn.dev33.satoken.annotation.SaCheckRole; -import cn.dev33.satoken.annotation.SaCheckSafe; +import cn.dev33.satoken.annotation.*; import cn.dev33.satoken.basic.SaBasicTemplate; import cn.dev33.satoken.basic.SaBasicUtil; import cn.dev33.satoken.config.SaTokenConfig; @@ -35,12 +30,12 @@ import cn.dev33.satoken.temp.SaTempInterface; public class XPluginImp implements Plugin { @Override - public void start(SolonApp app) { - Aop.context().beanAroundAdd(SaCheckPermission.class, SaTokenMethodInterceptor.INSTANCE); - Aop.context().beanAroundAdd(SaCheckRole.class, SaTokenMethodInterceptor.INSTANCE); - Aop.context().beanAroundAdd(SaCheckLogin.class, SaTokenMethodInterceptor.INSTANCE); - Aop.context().beanAroundAdd(SaCheckSafe.class, SaTokenMethodInterceptor.INSTANCE); - Aop.context().beanAroundAdd(SaCheckBasic.class, SaTokenMethodInterceptor.INSTANCE); + public void start(AopContext context) { + context.beanAroundAdd(SaCheckPermission.class, SaTokenMethodInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckRole.class, SaTokenMethodInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckLogin.class, SaTokenMethodInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckSafe.class, SaTokenMethodInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckBasic.class, SaTokenMethodInterceptor.INSTANCE); //集成初始化 @@ -51,67 +46,65 @@ public class XPluginImp implements Plugin { SaTokenConfig saTokenConfig = Solon.cfg().getBean("sa-token", SaTokenConfig.class); SaManager.setConfig(saTokenConfig); - Aop.getAsyn(SaTokenConfig.class, bw -> { + context.getWrapAsyn(SaTokenConfig.class, bw -> { SaManager.setConfig(bw.raw()); }); // 注入Dao Bean - Aop.getAsyn(SaTokenDao.class, bw -> { + context.getWrapAsyn(SaTokenDao.class, bw -> { SaManager.setSaTokenDao(bw.raw()); }); - // 注入二级上下文 Bean - Aop.getAsyn(SaTokenSecondContextCreator.class, bw->{ - SaTokenSecondContextCreator raw = bw.raw(); + // 注入二级上下文 Bean + context.getWrapAsyn(SaTokenSecondContextCreator.class, bw->{ + SaTokenSecondContextCreator raw = bw.raw(); SaManager.setSaTokenSecondContext(raw.create()); }); - + // 注入侦听器 Bean - Aop.getAsyn(SaTokenListener.class, bw->{ + context.getWrapAsyn(SaTokenListener.class, bw->{ SaManager.setSaTokenListener(bw.raw()); }); // 注入权限认证 Bean - Aop.getAsyn(StpInterface.class, bw->{ + context.getWrapAsyn(StpInterface.class, bw->{ SaManager.setStpInterface(bw.raw()); }); // 注入持久化 Bean - Aop.getAsyn(SaTokenDao.class, bw->{ + context.getWrapAsyn(SaTokenDao.class, bw->{ SaManager.setSaTokenDao(bw.raw()); }); // 临时令牌验证模块 Bean - Aop.getAsyn(SaTempInterface.class, bw->{ + context.getWrapAsyn(SaTempInterface.class, bw->{ SaManager.setSaTemp(bw.raw()); }); // Sa-Token-Id 身份凭证模块 Bean - Aop.getAsyn(SaIdTemplate.class, bw->{ - SaIdUtil.saIdTemplate = bw.raw(); + context.getWrapAsyn(SaIdTemplate.class, bw->{ + SaIdUtil.saIdTemplate = bw.raw(); }); - // Sa-Token Http Basic 认证模块 Bean - Aop.getAsyn(SaBasicTemplate.class, bw->{ - SaBasicUtil.saBasicTemplate = bw.raw(); + // Sa-Token Http Basic 认证模块 Bean + context.getWrapAsyn(SaBasicTemplate.class, bw->{ + SaBasicUtil.saBasicTemplate = bw.raw(); }); - // Sa-Token JSON 转换器 Bean - Aop.getAsyn(SaJsonTemplate.class, bw->{ - SaManager.setSaJsonTemplate(bw.raw()); + // Sa-Token JSON 转换器 Bean + context.getWrapAsyn(SaJsonTemplate.class, bw->{ + SaManager.setSaJsonTemplate(bw.raw()); }); - // Sa-Token 参数签名算法 Bean - Aop.getAsyn(SaSignTemplate.class, bw->{ - SaManager.setSaSignTemplate(bw.raw()); + // Sa-Token 参数签名算法 Bean + context.getWrapAsyn(SaSignTemplate.class, bw->{ + SaManager.setSaSignTemplate(bw.raw()); }); - // 自定义 StpLogic 对象 - Aop.getAsyn(StpLogic.class, bw->{ - StpUtil.setStpLogic(bw.raw()); + // 自定义 StpLogic 对象 + context.getWrapAsyn(StpLogic.class, bw->{ + StpUtil.setStpLogic(bw.raw()); }); - } - -} +} \ No newline at end of file From efd2a6468e9d20f7ec3c4b2443973c35bc47d13d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E5=85=89=E8=8C=82?= <10048892@qq.com> Date: Thu, 2 Jun 2022 01:34:42 +0000 Subject: [PATCH 011/144] =?UTF-8?q?update=20sa-token-doc/doc/fun/git-pr.md?= =?UTF-8?q?.=20=E5=8E=9F=E6=96=87:=203.=20=E7=82=B9=E5=87=BB=E5=8F=B3?= =?UTF-8?q?=E4=BE=A7=E5=9C=86=E5=9C=88=E6=8C=89=E9=92=AE=E5=90=8EGitee?= =?UTF-8?q?=E4=BC=9A=E8=87=AA=E5=8A=A8=E5=90=8C=E6=AD=A5=E4=B8=BB=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE,=20=E8=BF=99=E6=A0=B7=E5=B0=B1=E4=B8=8D=E7=94=A8?= =?UTF-8?q?=E5=90=91=E6=88=91=E4=B9=8B=E5=89=8D=E4=B8=80=E6=A0=B7,?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=A1=B9=E7=9B=AE=E5=8F=88=E9=87=8D=E6=96=B0?= =?UTF-8?q?fork=E4=BA=86.=20=E6=9B=B4=E6=96=B0=E4=B8=BA=EF=BC=9A=203.=20?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E5=8F=B3=E4=BE=A7=E5=9C=86=E5=9C=88=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E5=90=8EGitee=E4=BC=9A=E8=87=AA=E5=8A=A8=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E4=B8=BB=E9=A1=B9=E7=9B=AE,=20=E8=BF=99=E6=A0=B7?= =?UTF-8?q?=E5=B0=B1=E4=B8=8D=E7=94=A8=E5=83=8F=E6=88=91=E4=B9=8B=E5=89=8D?= =?UTF-8?q?=E4=B8=80=E6=A0=B7,=E5=88=A0=E9=99=A4=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=8F=88=E9=87=8D=E6=96=B0fork=E4=BA=86.=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=8E=9F=E5=9B=A0=EF=BC=9A=20=E5=90=91=E6=98=AF=E9=94=99?= =?UTF-8?q?=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/fun/git-pr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/fun/git-pr.md b/sa-token-doc/doc/fun/git-pr.md index e0bed738..363e5ca8 100644 --- a/sa-token-doc/doc/fun/git-pr.md +++ b/sa-token-doc/doc/fun/git-pr.md @@ -96,7 +96,7 @@ git clone 这里替换为复制后的链接 ![更新按钮](https://oss.dev33.cn/sa-token/doc/git-pr/code_10.png) -3. 点击右侧圆圈按钮后Gitee会自动同步主项目, 这样就不用向我之前一样,删除项目又重新fork了. +3. 点击右侧圆圈按钮后Gitee会自动同步主项目, 这样就不用像我之前一样,删除项目又重新fork了. ## 为什么在国内推荐Gitee 1. 近期Github下载网速较慢 From 1482780c4fcb152dab03aa2132eff575e8c00cb1 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 12 Jun 2022 22:43:45 +0800 Subject: [PATCH 012/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/up/not-cookie.md | 6 +++--- sa-token-doc/doc/use/route-check.md | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sa-token-doc/doc/up/not-cookie.md b/sa-token-doc/doc/up/not-cookie.md index 4aad8868..6f2e4018 100644 --- a/sa-token-doc/doc/up/not-cookie.md +++ b/sa-token-doc/doc/up/not-cookie.md @@ -5,7 +5,7 @@ 无Cookie:特指不支持Cookie功能的终端,通俗来讲就是我们常说的 —— **前后台分离模式** -常规PC端鉴权方法,一般由`Cookie模式`完成,而 Cookie 有两个特性: +常规 Web 端鉴权方法,一般由 `Cookie模式` 完成,而 Cookie 有两个特性: 1. 可由后端控制写入 2. 每次请求自动提交 @@ -13,8 +13,8 @@ 而在app、小程序等前后台分离场景中,一般是没有 Cookie 这一功能的,此时大多数人都会一脸懵逼,咋进行鉴权啊? 见招拆招,其实答案很简单: -- 不能后端控制写入了,就前端自己写入(难点在**后端如何将token传递到前端**) -- 每次请求不能自动提交了,那就手动提交(难点在**前端如何将token传递到后端**,同时**后端将其读取出来**) +- 不能后端控制写入了,就前端自己写入(难点在**后端如何将 Token 传递到前端**) +- 每次请求不能自动提交了,那就手动提交(难点在**前端如何将 Token 传递到后端**,同时**后端将其读取出来**) diff --git a/sa-token-doc/doc/use/route-check.md b/sa-token-doc/doc/use/route-check.md index 527b46db..e81c006a 100644 --- a/sa-token-doc/doc/use/route-check.md +++ b/sa-token-doc/doc/use/route-check.md @@ -117,8 +117,8 @@ SaRouter.match( StpUtil.isLogin() ).check( /* 要执行的校验函数 */ ); SaRouter.match( r -> StpUtil.isLogin() ).check( /* 要执行的校验函数 */ ); // 多个条件一起使用 -// 功能说明: 必须是 Get 方式的任意请求 -SaRouter.match(SaHttpMethod.GET).match("/**").check( /* 要执行的校验函数 */ ); +// 功能说明: 必须是 Get 请求 并且 请求路径以 `/user/` 开头 +SaRouter.match(SaHttpMethod.GET).match("/user/**").check( /* 要执行的校验函数 */ ); // 可以无限连缀下去 // 功能说明: 同时满足 Get 方式请求, 且路由以 /admin 开头, 路由中间带有 /send/ 字符串, 路由结尾不能是 .js 和 .css @@ -142,6 +142,8 @@ registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> { SaRouter.match("/**").check(r -> System.out.println("进入1")); SaRouter.match("/**").check(r -> System.out.println("进入2")).stop(); SaRouter.match("/**").check(r -> System.out.println("进入3")); + SaRouter.match("/**").check(r -> System.out.println("进入4")); + SaRouter.match("/**").check(r -> System.out.println("进入5")); })).addPathPatterns("/**"); ``` 如上示例,代码运行至第2条匹配链时,会在stop函数处提前退出整个匹配函数,从而忽略掉剩余的所有match匹配 @@ -149,7 +151,7 @@ registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> { 除了`stop()`函数,`SaRouter`还提供了 `back()` 函数,用于:停止匹配,结束执行,直接向前端返回结果 ``` java // 执行back函数后将停止匹配,也不会进入Controller,而是直接将 back参数 作为返回值输出到前端 -SaRouter.match("/user/back").back("参数"); +SaRouter.match("/user/back").back("要返回到前端的内容"); ``` stop() 与 back() 函数的区别在于: From 9d191cc675e239f822c53b8a412e57061a0b824e Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 14 Jun 2022 03:14:28 +0800 Subject: [PATCH 013/144] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=B5=9E=E5=8A=A9?= =?UTF-8?q?=E8=80=85=E5=90=8D=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/sa-token-donate.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sa-token-doc/doc/more/sa-token-donate.md b/sa-token-doc/doc/more/sa-token-donate.md index 5ee17408..007f3e2d 100644 --- a/sa-token-doc/doc/more/sa-token-donate.md +++ b/sa-token-doc/doc/more/sa-token-donate.md @@ -19,6 +19,11 @@ Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永 | 赞助人 | 赞助金额 | 留言 | 时间 | | :-------- | :-------- | :-------- | :-------- | +| [刘时立](https://gitee.com/liu-shili) | ¥ 10.0 | 非常棒的开源项目! | 2022-06-13 | +| [yuncai929](https://gitee.com/null_448_5562) | ¥ 10.0 | 感谢您的开源项目! | 2022-06-10 | +| [sun_2020](https://gitee.com/sun-two-thousand-and-twenty) | ¥ 50.0 | 感谢您的开源项目! | 2022-06-08 | +| [LZ](https://gitee.com/FUNKBOY) | ¥ 6.66 | 感谢您的开源项目!顺便踩一脚Spring Security,sa加油! | 2022-05-18 | +| [cray](https://gitee.com/hyy6300) | ¥ 10.0 | 感谢您的开源项目! | 2022-05-10 | | [别处理](https://gitee.com/zshnb) | ¥ 10.0 | 非常好的项目,希望能一直做下去 | 2022-05-01 | | [李洪星](https://gitee.com/li_hong_xing) | ¥ 10.0 | 解决了很多之前项目中遇到的问题。感谢您的开源项目! | 2022-04-29 | | [乡村阿土哥](https://gitee.com/895995040) | ¥ 10.0 | 感谢您的开源项目! | 2022-04-29 | From e9444852de5b40378da512200a2ec8cbe1eb62c0 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 14 Jun 2022 03:56:16 +0800 Subject: [PATCH 014/144] =?UTF-8?q?=E6=95=B4=E7=90=86=E6=A1=88=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- sa-token-doc/doc/README.md | 2 +- sa-token-doc/doc/more/link.md | 11 ++++++++--- sa-token-doc/index.html | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8b7e6ad1..218052da 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ ## Sa-Token 介绍 -**Sa-Token** 是一个轻量级 Java 权限认证框架,主要解决:**`登录认证`**、**`权限认证`**、**`Session会话`**、**`单点登录`**、**`OAuth2.0`**、**`微服务网关鉴权`** +**Sa-Token** 是一个轻量级 Java 权限认证框架,主要解决:**登录认证**、**权限认证**、**单点登录**、**OAuth2.0**、**分布式Session会话**、**微服务网关鉴权** 等一系列权限相关问题。 diff --git a/sa-token-doc/doc/README.md b/sa-token-doc/doc/README.md index d54abb2f..d4a702c5 100644 --- a/sa-token-doc/doc/README.md +++ b/sa-token-doc/doc/README.md @@ -24,7 +24,7 @@ ## Sa-Token 介绍 -**Sa-Token** 是一个轻量级 Java 权限认证框架,主要解决:**`登录认证`**、**`权限认证`**、**`Session会话`**、**`单点登录`**、**`OAuth2.0`**、**`微服务网关鉴权`** +**Sa-Token** 是一个轻量级 Java 权限认证框架,主要解决:**登录认证**、**权限认证**、**单点登录**、**OAuth2.0**、**分布式Session会话**、**微服务网关鉴权** 等一系列权限相关问题。 Sa-Token 的 API 设计非常简单,有多简单呢?以登录认证为例,你只需要: diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index 7b020f57..dab9d4c8 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -15,8 +15,6 @@ ### 使用 Sa-Token 的开源项目: -- [[ iot-kit ]](https://gitee.com/iotkit-open-source/iotkit-parent):一个轻量级低门槛的物联网平台,包含了多协议设备接入、规则引擎、第三方平台接入、智能家居小程序等模块的项目,基于SpringBoot架构并集成了Sa-Token的OAuth2认证。 - - [[ Sa-Plus ]](https://gitee.com/click33/sa-plus):一个基于 SpringBoot 架构的快速开发框架,内置代码生成器 - [[ jthink ]](https://gitee.com/wtsoftware/jthink): 一个基于 SpringBoot + Sa-Token + Thymeleaf 的博客系统 @@ -63,8 +61,15 @@ - [[ SpringMvc+Sa-Token ]](https://gitee.com/SRD_01/spring-mvc-sa-token): Jsp+SpringMVC+SSO+Sa-Token+Redis | Spring MVC 集成 SaToken Demo 项目 - - [[ 自定义快速搭建平台 ]](https://gitee.com/CodeLiQing/custom-quick-build-platform): MybatisPlus+SpringMVC+SSO+Sa-Token+Redis | 基于springboot+as-token+neety+代码生产器(vm实现)| 以及前端vue的element-ui 和大屏框架DataV + +- [[ iot-kit ]](https://gitee.com/iotkit-open-source/iotkit-parent):一个轻量级低门槛的物联网平台,包含了多协议设备接入、规则引擎、第三方平台接入、智能家居小程序等模块的项目,基于SpringBoot架构并集成了Sa-Token的OAuth2认证。 + +- [[ 拾壹博客 ]](https://gitee.com/quequnlong/shiyi-blog.git):一款vue+springboot前后端分离的博客系统,博客后台管理系统使用了vue+elmentui开发,后端使用Sa-Token进行权限管理,支持动态菜单权限,动态定时任务,文件支持本地和七牛云上传,使用ElasticSearch作为全文检索服务,支持QQ、微博、码云登录。 + + + +
diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 5ec5726a..ee947a8e 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -112,11 +112,11 @@

权限认证、角色认证、会话二级认证、注解鉴权、路由鉴权……多种姿势灵活鉴权

-

🔥️ 踢人下线

+

⛏️ 踢人下线

强制注销、踢人下线、账号封禁、身份切换、自动续签 …… 提供完善的会话管理方案

-

⭐️ Redis集成

+

🔎️ Redis集成

提供 Redis 集成方案、项目重启数据不丢失、多系统数据互通,可自定义数据持久化策略

From f10a16639adae3770eaf7bd0343ffa5f8f816057 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 14 Jun 2022 08:34:23 +0800 Subject: [PATCH 015/144] =?UTF-8?q?=E6=96=87=E6=A1=A3=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A1=88=E4=BE=8B=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/link.md | 5 ++- sa-token-doc/index.css | 34 +++++++++++++++ sa-token-doc/index.html | 81 +++++++++++++++++++++++++++++++++-- 3 files changed, 115 insertions(+), 5 deletions(-) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index dab9d4c8..38fe5c3c 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -10,12 +10,13 @@ > 经过 Sa-Token 开发组审核通过后: > - 将展示在此页面。 > - 在 Sa-Token 交流群中宣传推广,为项目带来流量。 +> - 按照 star 量排序择取前六名展示在官网首页。 --- ### 使用 Sa-Token 的开源项目: -- [[ Sa-Plus ]](https://gitee.com/click33/sa-plus):一个基于 SpringBoot 架构的快速开发框架,内置代码生成器 +1. [[ Sa-Plus ]](https://gitee.com/click33/sa-plus):一个基于 SpringBoot 架构的快速开发框架,内置代码生成器 - [[ jthink ]](https://gitee.com/wtsoftware/jthink): 一个基于 SpringBoot + Sa-Token + Thymeleaf 的博客系统 @@ -31,7 +32,7 @@ - [[ RuoYi-Cloud-Plus ]](https://gitee.com/JavaLionLi/RuoYi-Cloud-Plus):重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba + Sa-Token + Dubbo + Mybatis-Plus + Xxl-Job 全方位升级 定期同步 -- [[ SpringBoot_v2 ]](https://gitee.com/bdj/SpringBoot_v2/tree/sa-token/):SpringBoot_v2项目是努力打造springboot框架的极致细腻的脚手架。 +- [[ SpringBoot_v2 ]](https://gitee.com/bdj/SpringBoot_v2):SpringBoot_v2项目是努力打造springboot框架的极致细腻的脚手架。 - [[ Sa-Token-Study ]](https://gitee.com/click33/sa-token-study):以demo示例的方式讲解 Sa-Token 源码涉及到的技术点,连载中…… diff --git a/sa-token-doc/index.css b/sa-token-doc/index.css index c547deeb..86d32874 100644 --- a/sa-token-doc/index.css +++ b/sa-token-doc/index.css @@ -2,6 +2,7 @@ /* 总 */ *{margin: 0px; padding: 0px;} body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica Neue","Arial,sans-serif";} + .s-width{width: 1000px; margin: auto;} /* 栏目标题 */ .s-title{color: #000; margin-top: 90px; margin-bottom: 50px;} @@ -102,6 +103,39 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica .re-text a{color: #0969da; text-decoration: none;} .re-text a:hover{border-bottom: 1px #0969da solid;} +/* -------- 集成案例 --------- */ +.s-case-box{justify-content: space-between;} +.s-case{border: 1px #eee solid; flex: 0 0 31.5%; margin-top: 30px; text-align: left; box-sizing: border-box; padding-bottom: 16px; overflow: hidden;} +.s-case{position: relative;} +.s-case-link{display: block; width: 100%; height: 0px; padding-bottom: 50%; position: relative; overflow: hidden;} +.s-case-link img{width: 100%; height: 100%; object-fit: cover; object-position: center; position: absolute;} +.s-case-link img{transition: all 0.3s;} +.s-case-title,.s-case-intro{padding: 0 16px;} +.s-case-title{margin-top: 20px; font-size: 18px; font-weight: 400; color: #333; font-family: "microsoft yahei";} +.s-case-intro{margin-top: 10px; font-size: 14px; line-height: 20px; color: #777; word-break:break-all;} +.s-author{color: #ff5722; border: 1px #ff5722 solid; position: absolute; right: 20px; display: inline-block;} +.s-author{padding: 0 5px; font-size: 12px; transform: translate(0, -25px);} + + +/* 悬浮动画 */ +.s-case:hover img{transform: scale(1.3, 1.3); } +.s-case img:hover{cursor: pointer;} +.s-case:hover .s-case-link:after {background-color: rgba(0, 0, 0, .35); color: #FFF;} +.s-case .s-case-link:after { + content: "详情"; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0); + transition: all .4s; + text-align: center; + line-height: 10; + color: rgba(0,0,0,0); + cursor: pointer; +} + /* -------- 使用公司 --------- */ .com-box-f{padding: 1em 1em; padding-bottom: 30px; text-align: center;} diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index ee947a8e..4a7504a1 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -147,13 +147,85 @@
+ +
+
+
+

优秀开源集成案例

+
+ +
+ + + +

SpringBoot_v2

+ 开源oschina +

努力打造 springboot 框架的极致细腻的脚手架,原生纯净。

+
+ +
+ + + +

RuoYi-Vue-Plus

+ 疯狂的狮子Li +

重写 RuoYi-Vue 所有功能,集成 Sa-Token、Mybatis-Plus、Hutool 定期同步

+
+ +
+ + + +

Sa-Plus

+ 孔明 +

一个基于 SpringBoot 的快速开发框架,内置代码生成器

+
+ +
+ + + +

EasyAdmin

+ laker +

轻量级的后台管理系统脚手架,内置代码生成器、权限管理、工作流引擎等

+
+ +
+ + + +

RuoYi-Cloud-Plus

+ 疯狂的狮子Li +

重写 RuoYi-Cloud 所有功能 整合 SpringCloudAlibaba、Dubbo3.0、Sa-Token

+
+ +
+ + + +

dcy-fast

+ 青年 +

一个基于 SpringBoot + Sa-Token + Mybatis-Plus 的后台管理系统

+
+ +
+
+ + 如果您的开源项目也使用了 Sa-Token,您可以 + 在此 + 提交 + +
+
+
+

-

正在使用 Sa-Token 的公司 / 机构

+

正在使用 Sa-Token 的企业 / 机构

-

- (如果您的项目也使用了 Sa-Token,您可以 +

+ (如果您的企业也使用了 Sa-Token,您可以 在此 提交)

From e4180aff2d93455cc9a44e4ff6831ea49103f160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E6=95=B2=E4=BB=A3=E7=A0=81=E7=9A=84=E5=B0=8F?= =?UTF-8?q?=E5=BA=86?= <1578442339@qq.com> Date: Tue, 14 Jun 2022 01:26:14 +0000 Subject: [PATCH 016/144] =?UTF-8?q?update=20sa-token-doc/doc/more/link.md.?= =?UTF-8?q?=20=E7=94=B1=E4=BA=8E=E9=87=8D=E6=9E=84=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=8B=E8=87=AA=E5=AE=9A=E4=B9=89=E5=BC=80=E5=8F=91=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=20=E9=87=8D=E6=96=B0=E5=86=99=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=8B=E4=BB=8B=E7=BB=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/link.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index 38fe5c3c..5b4f4191 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -62,7 +62,7 @@ - [[ SpringMvc+Sa-Token ]](https://gitee.com/SRD_01/spring-mvc-sa-token): Jsp+SpringMVC+SSO+Sa-Token+Redis | Spring MVC 集成 SaToken Demo 项目 -- [[ 自定义快速搭建平台 ]](https://gitee.com/CodeLiQing/custom-quick-build-platform): MybatisPlus+SpringMVC+SSO+Sa-Token+Redis | 基于springboot+as-token+neety+代码生产器(vm实现)| 以及前端vue的element-ui 和大屏框架DataV +- [[ QuickBuild ]](https://gitee.com/CodeLiQing/custom-quick-build-platform): 快速构建 | 基于springboot+as-token+neety+代码生产器(生成vue页面和增删改查代码)| 以及前端vue3和字节arco.design框架整合 - [[ iot-kit ]](https://gitee.com/iotkit-open-source/iotkit-parent):一个轻量级低门槛的物联网平台,包含了多协议设备接入、规则引擎、第三方平台接入、智能家居小程序等模块的项目,基于SpringBoot架构并集成了Sa-Token的OAuth2认证。 From 3ef954b7b49c93f8c7f92a5c1cfd0dea903dcace Mon Sep 17 00:00:00 2001 From: dongchunyu <1540770111@qq.com> Date: Tue, 14 Jun 2022 10:14:31 +0800 Subject: [PATCH 017/144] =?UTF-8?q?feat=EF=BC=9A=E5=A2=9E=E5=8A=A0dcy-fast?= =?UTF-8?q?-cloud=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/link.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index 5b4f4191..032def22 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -68,6 +68,8 @@ - [[ 拾壹博客 ]](https://gitee.com/quequnlong/shiyi-blog.git):一款vue+springboot前后端分离的博客系统,博客后台管理系统使用了vue+elmentui开发,后端使用Sa-Token进行权限管理,支持动态菜单权限,动态定时任务,文件支持本地和七牛云上传,使用ElasticSearch作为全文检索服务,支持QQ、微博、码云登录。 +- [[ dcy-fast-cloud ]](https://gitee.com/dcy421/dcy-fast-cloud):一个基于 SpringCloudAlibaba + Sa-Token + dubbo2.7.8 + Seata + knife4j + Mybatis-Plus + MapStruct + 的后台管理系统,前端vue-element-admin,并且内置代码生成器+动态路由权限等功能 + From 58e3bb72a57e038c4b0f8b715a2cb9926376426f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E6=95=B2=E4=BB=A3=E7=A0=81=E7=9A=84=E5=B0=8F?= =?UTF-8?q?=E5=BA=86?= <1578442339@qq.com> Date: Tue, 14 Jun 2022 02:28:01 +0000 Subject: [PATCH 018/144] =?UTF-8?q?update=20sa-token-doc/doc/more/link.md.?= =?UTF-8?q?=20=E6=94=B9=E6=AD=A3sa-token=E5=90=8D=E5=AD=97=20=E4=B9=8B?= =?UTF-8?q?=E5=89=8D=E6=89=93=E9=94=99=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/link.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index 5b4f4191..258f1809 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -62,7 +62,7 @@ - [[ SpringMvc+Sa-Token ]](https://gitee.com/SRD_01/spring-mvc-sa-token): Jsp+SpringMVC+SSO+Sa-Token+Redis | Spring MVC 集成 SaToken Demo 项目 -- [[ QuickBuild ]](https://gitee.com/CodeLiQing/custom-quick-build-platform): 快速构建 | 基于springboot+as-token+neety+代码生产器(生成vue页面和增删改查代码)| 以及前端vue3和字节arco.design框架整合 +- [[ QuickBuild ]](https://gitee.com/CodeLiQing/custom-quick-build-platform): 快速构建 | 基于springboot+sa-token+neety+代码生产器(生成vue页面和增删改查代码)| 以及前端vue3和字节arco.design框架整合 - [[ iot-kit ]](https://gitee.com/iotkit-open-source/iotkit-parent):一个轻量级低门槛的物联网平台,包含了多协议设备接入、规则引擎、第三方平台接入、智能家居小程序等模块的项目,基于SpringBoot架构并集成了Sa-Token的OAuth2认证。 From 298d0161e097931688ea4418c8519e1866f5d18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=95=E9=87=91=E6=B3=BD?= <1098696801@qq.com> Date: Tue, 14 Jun 2022 06:06:07 +0000 Subject: [PATCH 019/144] update sa-token-doc/doc/more/link.md. --- sa-token-doc/doc/more/link.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index 09a47210..bf177a70 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -70,6 +70,8 @@ - [[ dcy-fast-cloud ]](https://gitee.com/dcy421/dcy-fast-cloud):一个基于 SpringCloudAlibaba + Sa-Token + dubbo2.7.8 + Seata + knife4j + Mybatis-Plus + MapStruct + 的后台管理系统,前端vue-element-admin,并且内置代码生成器+动态路由权限等功能 +- [[ magic-boot ]](https://gitee.com/ssssssss-team/magic-boot):基于 magic-api + Sa-Token 搭建的快速开发平台,可以实现在浏览器编写Vue代码,既改即生效 + From fc78fd867f15f4a783a3fa3eee993f8b964196e6 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 17 Jun 2022 22:35:02 +0800 Subject: [PATCH 020/144] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8D=90=E8=B5=A0?= =?UTF-8?q?=E8=80=85=E5=90=8D=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/sa-token-donate.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sa-token-doc/doc/more/sa-token-donate.md b/sa-token-doc/doc/more/sa-token-donate.md index 007f3e2d..2ff469c8 100644 --- a/sa-token-doc/doc/more/sa-token-donate.md +++ b/sa-token-doc/doc/more/sa-token-donate.md @@ -19,6 +19,8 @@ Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永 | 赞助人 | 赞助金额 | 留言 | 时间 | | :-------- | :-------- | :-------- | :-------- | +| [风如歌](https://gitee.com/the-wind-is-like-a-song) | ¥ 10.0 | 这个框架简直满足了我所有对于安全框架的需求,赞一个,加油sa-token加油中国开源! | 2022-06-17 | +| [qiuyue](https://gitee.com/bmlt) | ¥ 10.0 | satoken牛逼 | 2022-06-16 | | [刘时立](https://gitee.com/liu-shili) | ¥ 10.0 | 非常棒的开源项目! | 2022-06-13 | | [yuncai929](https://gitee.com/null_448_5562) | ¥ 10.0 | 感谢您的开源项目! | 2022-06-10 | | [sun_2020](https://gitee.com/sun-two-thousand-and-twenty) | ¥ 50.0 | 感谢您的开源项目! | 2022-06-08 | @@ -80,7 +82,7 @@ Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永 | [知知](https://gitee.com/double_zhi) | ¥ 10 | 感谢您的开源项目! | 2020-12-15 | | [省长](https://gitee.com/click33) | ¥ 10 | java中最好用的权限认证框架! | 2020-12-15 | -感谢每一位小伙伴的热心支持! +感谢每一位小伙伴的热心支持 ❤️ ❤️ ❤️ ! From e44f74c481136bda7d7f64647011fa053bfe5daf Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 18 Jun 2022 10:08:04 +0800 Subject: [PATCH 021/144] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20issue=20=E6=8F=90?= =?UTF-8?q?=E9=97=AE=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitee/ISSUE_TEMPLATE.md | 19 +--------- .github/ISSUE_TEMPLATE.md | 19 +--------- sa-token-doc/doc/_sidebar.md | 1 + sa-token-doc/doc/fun/issue-template.md | 51 ++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 36 deletions(-) create mode 100644 sa-token-doc/doc/fun/issue-template.md diff --git a/.gitee/ISSUE_TEMPLATE.md b/.gitee/ISSUE_TEMPLATE.md index 5f14499d..7dbc6e95 100644 --- a/.gitee/ISSUE_TEMPLATE.md +++ b/.gitee/ISSUE_TEMPLATE.md @@ -1,18 +1 @@ -### 使用版本: -请提供一下版本号 - - -### 报错信息: -请提供报错的详细信息 - - -### 希望结果: -相比于已发生的报错,您希望看到什么样的运行结果 - - -### 复现步骤: -如果复现步骤比较复杂,请将 demo 上传到 git 并留下地址 - - -备注:您提供的信息越充足,我们将越能快速的定位错误 - +请在 [issue 提问模板](https://sa-token.dev33.cn/doc/index.html#/fun/issue-template) 复制模板进行提交 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 5f14499d..7dbc6e95 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,18 +1 @@ -### 使用版本: -请提供一下版本号 - - -### 报错信息: -请提供报错的详细信息 - - -### 希望结果: -相比于已发生的报错,您希望看到什么样的运行结果 - - -### 复现步骤: -如果复现步骤比较复杂,请将 demo 上传到 git 并留下地址 - - -备注:您提供的信息越充足,我们将越能快速的定位错误 - +请在 [issue 提问模板](https://sa-token.dev33.cn/doc/index.html#/fun/issue-template) 复制模板进行提交 diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 1a19d128..310f86b5 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -92,6 +92,7 @@ - [技术选型:SSO 与 OAuth2 对比](/fun/sso-vs-oauth2) - [自定义 SaTokenContext 指南](/fun/sa-token-context) - [框架源码所有技术栈](/fun/tech-stack) + - [issue 提问模板](/fun/issue-template) - [为Sa-Token贡献代码](/fun/git-pr) - [Sa-Token开源大事记](/fun/timeline) - [Sa-Token框架掌握度--在线考试](/fun/sa-token-test) diff --git a/sa-token-doc/doc/fun/issue-template.md b/sa-token-doc/doc/fun/issue-template.md new file mode 100644 index 00000000..b9f5b4a2 --- /dev/null +++ b/sa-token-doc/doc/fun/issue-template.md @@ -0,0 +1,51 @@ +# issue 提问模板 + +请在新建 issue 时,尽量复制以下格式进行提交 + +--- + + +### bug反馈: +``` js +### 使用版本: + + +### 报错信息: + + +### 希望结果: + + +### 复现步骤: + + +< 备注:如果复现步骤比较复杂,请将 demo 上传到 gitee 并留下地址 > +``` + + +### 功能提问: +``` js +### 对以下问题有疑问: + + +< 备注:请尽量详细描述问题所在 > +``` + + +### 建议增加新功能: +``` js +### 建议增加的新功能: + + +### 应用场景阐述: + + +< 备注:请尽量详细描述功能应用场景 > +``` + + + + + + + From 3cfcf9a602f33f4453a0051ea8219030de04e5e2 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 18 Jun 2022 10:09:30 +0800 Subject: [PATCH 022/144] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20issue=20=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitee/ISSUE_TEMPLATE.md | 3 ++- .github/ISSUE_TEMPLATE.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitee/ISSUE_TEMPLATE.md b/.gitee/ISSUE_TEMPLATE.md index 7dbc6e95..cac78cfb 100644 --- a/.gitee/ISSUE_TEMPLATE.md +++ b/.gitee/ISSUE_TEMPLATE.md @@ -1 +1,2 @@ -请在 [issue 提问模板](https://sa-token.dev33.cn/doc/index.html#/fun/issue-template) 复制模板进行提交 +请在以下地址复制 issue 模板进行提交: +https://sa-token.dev33.cn/doc/index.html#/fun/issue-template diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 7dbc6e95..cac78cfb 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1 +1,2 @@ -请在 [issue 提问模板](https://sa-token.dev33.cn/doc/index.html#/fun/issue-template) 复制模板进行提交 +请在以下地址复制 issue 模板进行提交: +https://sa-token.dev33.cn/doc/index.html#/fun/issue-template From 1ee402b2412d2a9313e4fe26e9d39a9eea54dab0 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 18 Jun 2022 10:15:08 +0800 Subject: [PATCH 023/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=20issus=20=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/fun/issue-template.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sa-token-doc/doc/fun/issue-template.md b/sa-token-doc/doc/fun/issue-template.md index b9f5b4a2..98f3f45e 100644 --- a/sa-token-doc/doc/fun/issue-template.md +++ b/sa-token-doc/doc/fun/issue-template.md @@ -1,6 +1,13 @@ # issue 提问模板 -请在新建 issue 时,尽量复制以下格式进行提交 +> 请在新建 issue 时,尽量复制模板格式进行提交 +> +> 1. 提交之前率先参考 [Sa-Token 常见问题解答](https://sa-token.dev33.cn/doc/index.html#/more/common-questions) 以及善用 Gitee issues 搜索功能,查阅问题是否已有答案,已存在的 issue 就不要再重复提交了。 +> 2. 问题已得到处理的 issue 请大家及时手动关闭,如果超过24小时没有追问,我们将默认提交者已找到解决方案,关闭issue。 +> 3. 有时候 issue 提交之后,没有得到及时回复,大家可以加入QQ群@管理员寻求帮助。 +> 4. 请大家新建 issue 时删除不必要的模板信息、精简语句、**做好代码排版**,对于不方便描述的业务场景,可参阅 [Sa-Token 名词解释](https://sa-token.dev33.cn/doc/index.html#/more/noun-intro) 方便组织语句,这样有助于减低大家的沟通成本。 + + --- From dfc8b59a4d46ce2dc3706d70267fa49cb9d94cde Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 18 Jun 2022 15:52:09 +0800 Subject: [PATCH 024/144] =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8D=9A=E5=AE=A2=E6=A0=8F=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/_sidebar.md | 1 + sa-token-doc/doc/index-backup.html | 1 + sa-token-doc/doc/index.html | 1 + sa-token-doc/doc/more/blog.md | 51 ++++++++++++++++++++++++++++++ sa-token-doc/index.css | 18 +++++++---- sa-token-doc/index.html | 9 +++++- 6 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 sa-token-doc/doc/more/blog.md diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 310f86b5..7305cc64 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -73,6 +73,7 @@ - **其它** - [更新日志](/more/update-log) - [框架生态](/more/link) + - [框架博客](/more/blog) - [推荐公众号](/more/tj-gzh) - [赞助 Sa-Token](/more/sa-token-donate) diff --git a/sa-token-doc/doc/index-backup.html b/sa-token-doc/doc/index-backup.html index 041c7074..f4687a7a 100644 --- a/sa-token-doc/doc/index-backup.html +++ b/sa-token-doc/doc/index-backup.html @@ -64,6 +64,7 @@ 首页 文档 生态 + 博客 赞助 🔥 SSO商业版
diff --git a/sa-token-doc/doc/index.html b/sa-token-doc/doc/index.html index 1b299916..557be353 100644 --- a/sa-token-doc/doc/index.html +++ b/sa-token-doc/doc/index.html @@ -65,6 +65,7 @@ 首页 文档 生态 + 博客 赞助 🔥 SSO商业版
diff --git a/sa-token-doc/doc/more/blog.md b/sa-token-doc/doc/more/blog.md new file mode 100644 index 00000000..df76ffdf --- /dev/null +++ b/sa-token-doc/doc/more/blog.md @@ -0,0 +1,51 @@ +# 框架博客 + +> 此页面收集 Sa-Token 相关技术文章,欢迎大家投稿(不限平台), +> 直接提交 [pr](https://gitee.com/dromara/sa-token/tree/dev/sa-token-doc/doc/more/blog.md) 即可(按照发表日期倒叙)。 + +--- + +- [[ 掘金 ] sa-token过期后WebSocket提示过期](https://juejin.cn/post/7103446095987998733) (2022-5-30) + +- [[ 掘金 ] Sa-Token 单点登录 SSO模式二 URL重定向传播会话示例](https://juejin.cn/post/7102733249088077854) (2022-5-28) + +- [[ 掘金 ] SaToken技术分享](https://juejin.cn/post/7097967875670933535) (2022-5-15) + +- [[ 掘金 ] SpringMVC配置sa-Token](https://juejin.cn/post/7081471627766005790) (2022-4-1) + +- [[ 掘金 ] 【SpringCloud-Alibaba系列教程】13.gateway网关结合Sa-token进行登录鉴权](https://juejin.cn/post/7070805258296885285) (2022-3-3) + +- [[ 掘金 ] Spring Cloud Gateway 集成Sa-Token](https://juejin.cn/post/7069748160087719967) (2022-2-28) + +- [[ 掘金 ] Java轻量级权限认证框架 Sa-Token 初体验](https://juejin.cn/post/7068105371839102983) (2022-2-24) + +- [[ 掘金 ] 使用 Sa-Token 解决 WebSocket 握手身份认证](https://juejin.cn/post/7064232762664255525) (2022-2-14) + +- [[ 掘金 ] Springboot插件集成(三)-权限认证插件sa-token](https://juejin.cn/post/7051872914458542093) (2022-1-11) + +- [[ 公众号 ] 还在用Spring Security?推荐你一款使用简单、功能强大的权限认证框架](https://mp.weixin.qq.com/s/L2KOgwJcXCxrSAV8bPJsJQ) (2021-10-8) + +- [[ 公众号 ] Spring Security太复杂?试试这个轻量、强大、优雅的权限认证框架!](https://mp.weixin.qq.com/s/BWziNxRZH29F2v4Tmb5meA) + +- [[ 掘金 ] Sa-Token之注解鉴权:优雅的将鉴权与业务代码分离!](https://juejin.cn/post/7007102435705487396) (2021-9-13) + +- [[ 掘金 ] 开箱即用!看看人家的微服务权限解决方案,那叫一个优雅!](https://juejin.cn/post/7003141949259513887) (2021-9-2) + +- [[ 掘金 ] 再见Spring Security!推荐一款功能强大的Java权限认证框架,用起来够优雅!](https://juejin.cn/post/7000174417846222878) (2021-8-25) + +- [[ 掘金 ] 史上功能最全的 Java 权限认证框架!](https://juejin.cn/post/6986174013647093773) (2021-7-18) + +- [[ 掘金 ] 一个项目搞定Java权限认证框架,二十多个特性开箱即用](https://juejin.cn/post/6985077113288130574) (2021-7-15) + +- [[ 掘金 ] 从零搭建开发脚手架 集成认证授权 sa-token(尝鲜)](https://juejin.cn/post/6950163768533843999) (2021-4-12) + +- [[ 掘金 ] 权限认证就它了Sa-Token](https://juejin.cn/post/6938747514837434376) (2021-3-12) + +- [[ 掘金 ] sa-token之前后台分离模式下如何完成权限认证](https://juejin.cn/post/6937219472507797535) (2021-03-8) + +- [[ 掘金 ] 一个登录功能也能玩出这么多花样?sa-token带你轻松搞定多地登录、单地登录、同端互斥登录](https://juejin.cn/post/6917884159491276808) (2021-1-15) + +- [[ 掘金 ] sa-token v1.9.0 版本已发布,带来激动人心新特性:同端互斥登录](https://juejin.cn/post/6914612737020526599) (2021-1-6) + +- [[ 掘金 ] Spring Boot 系列教程 | 第一百一篇:SpringBoot整合sa-token权限框架](https://juejin.cn/post/6875525673897869319) (2020-9-23) + diff --git a/sa-token-doc/index.css b/sa-token-doc/index.css index 86d32874..b39167e2 100644 --- a/sa-token-doc/index.css +++ b/sa-token-doc/index.css @@ -89,8 +89,8 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica .feature-z .s-title{font-size: 30px; font-weight: 400; margin-top: 70px; margin-bottom: 40px;} .feature-z{color: rgb(128, 128, 128); text-align: center; box-sizing: border-box; line-height: 24px; font-size: 16px;} -.feature-box{margin-top: 50px; margin-bottom: 70px; display: flex; flex-wrap: wrap; justify-content: flex-start;} -.feature{border: 0px #000 solid; flex: 1; min-width: 33%; max-width: 33%; text-align: left; padding: 1.8em 1.2em; box-sizing: border-box;} +.feature-box{margin-top: 50px; margin-bottom: 70px; display: flex; flex-wrap: wrap; justify-content: space-between; /* justify-content: flex-start; */} +.feature{border: 0px #000 solid; flex: 0 0 33%; text-align: left; padding: 1.8em 1.2em; box-sizing: border-box;} .feature h2{font-size: 22px; color: #000; font-weight: 400;} .feature p{margin-top: 14px; font-size: 16px; color: #4e6e8e;} @@ -141,14 +141,14 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica .com-box-f{padding: 1em 1em; padding-bottom: 30px; text-align: center;} .com-box-f h2{font-size: 30px; color: #000; font-weight: 400;} .com-box{display: flex; flex-wrap: wrap; width: 100%; margin-bottom: 50px; justify-content: flex-start;} -.com-box a{flex: 1; display: block; cursor: pointer; border: 0px #ddd solid;} -.com-box a{min-width: 13%; max-width: 14%; margin: 5px; line-height: 75px;} +.com-box a{display: block; flex: 0 0 13%; margin: 5px; cursor: pointer; border: 0px #ddd solid;} +.com-box a{line-height: 75px;} .com-box a img{transition: all 0.2s; vertical-align: middle; min-width: 60%; max-width: 100%; max-height: 100%;} .com-box a img:hover{transform: scale(1.05, 1.05);} .com-box-you a img:hover{transform: none;} /* -------- 友情链接 --------- */ -.com-box-you a{min-width: 13%; max-width: 14%; line-height: 60px; height: 60px; margin: 10px;} +.com-box-you a{flex: 0 0 14.5%; line-height: 60px; height: 60px; margin: 10px;} .com-box-you a img{min-width: 60%; max-width: 100%; vertical-align: middle; max-height: 100%;} /* -------- 底部 - 连接 --------- */ @@ -188,10 +188,14 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica .feature{min-width: 100%;} .com-box-f{padding: 0em;} - .com-box a{min-width: 90%;} + .com-box{justify-content: space-around;} + .com-box a{flex: 0 0 90%;} + + .s-case-box{justify-content: space-around;} + .s-case{flex: 0 0 90%;} .footer-r-b{display: block;} - .ss-box{display: block; width: 90%; margin: 0px; padding-left: 1.5em;} + .ss-box{display: block; text-align: center; width: 90%; margin: 0px; padding-left: 1.5em;} /* .s-header{position: static;} */ footer{position: static; line-height: 40px;} diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 4a7504a1..416c7ea5 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -31,6 +31,7 @@ 首页 文档 生态 + 博客 赞助 🔥 SSO商业版
@@ -147,7 +148,7 @@
- +
@@ -299,6 +300,12 @@ + + + + + +

From 3f0ee49cc0623453e2939aa34b99a9b84f4dc46a Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 18 Jun 2022 15:56:46 +0800 Subject: [PATCH 025/144] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=A1=88=E4=BE=8B?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 416c7ea5..8988d9ae 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -300,12 +300,12 @@ - - - + + +

From dfefb04b2f5b7d6044475a84e7ddb90aca1372cd Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 18 Jun 2022 16:32:19 +0800 Subject: [PATCH 026/144] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8D=9A=E5=AE=A2?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/blog.md | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/sa-token-doc/doc/more/blog.md b/sa-token-doc/doc/more/blog.md index df76ffdf..df6235bd 100644 --- a/sa-token-doc/doc/more/blog.md +++ b/sa-token-doc/doc/more/blog.md @@ -11,23 +11,49 @@ - [[ 掘金 ] SaToken技术分享](https://juejin.cn/post/7097967875670933535) (2022-5-15) +- [[今日头条] SpringCloud Gateway配置Nacos服务发现,Sa-Token实现接口授权](https://www.toutiao.com/article/7089584645368578567/) (2022-04-24) + +- [[ CSDN ] 使用sa-token 进行权限控制](https://blog.csdn.net/u012389318/article/details/124098705) (2022-4-13) + - [[ 掘金 ] SpringMVC配置sa-Token](https://juejin.cn/post/7081471627766005790) (2022-4-1) +- [[ CSDN ] 【SpringBoot】59、SpringBoot使用Sa-Token-Quick-Login插件快速登录认证](https://lizhou.blog.csdn.net/article/details/123571910) (2022-03-30) + +- [[ CSDN ] 【Sa-Token】1、Sa-Token实现登录功能](https://lizhou.blog.csdn.net/article/details/119301185) (2022-03-30) + - [[ 掘金 ] 【SpringCloud-Alibaba系列教程】13.gateway网关结合Sa-token进行登录鉴权](https://juejin.cn/post/7070805258296885285) (2022-3-3) +- [[ CSDN ] Sa-Token的Token有效期和临时有效期的区别](https://blog.csdn.net/ControlDemo/article/details/123177825) (2022-02-28) + - [[ 掘金 ] Spring Cloud Gateway 集成Sa-Token](https://juejin.cn/post/7069748160087719967) (2022-2-28) - [[ 掘金 ] Java轻量级权限认证框架 Sa-Token 初体验](https://juejin.cn/post/7068105371839102983) (2022-2-24) +- [[ CSDN ] Sa-Token获取当前所有可用Token](https://blog.csdn.net/ControlDemo/article/details/122940634) (2022-02-15) + - [[ 掘金 ] 使用 Sa-Token 解决 WebSocket 握手身份认证](https://juejin.cn/post/7064232762664255525) (2022-2-14) +- [[ CSDN ] sa-token配置路由拦截放行Swagger路径](https://blog.csdn.net/ControlDemo/article/details/122885782) (2022-02-11) + +- [[ CSDN ] sa-token 多端登录思路和遇到的坑](https://blog.csdn.net/ControlDemo/article/details/122428512) (2022-1-28) + +- [[ CSDN ] 【RuoYi-Vue-Plus】学习笔记 13 - Sa-Token(三)退出登录流程(Sa-Token 源码)](https://blog.csdn.net/Michelle_Zhong/article/details/122691698) (2022-01-25) + +- [[ CSDN ] 【RuoYi-Vue-Plus】学习笔记 12 - Sa-Token(二)通过注解校验用户权限(Sa-Token 源码)](https://blog.csdn.net/Michelle_Zhong/article/details/122526722) (2022-01-16) + +- [[ CSDN ] 【RuoYi-Vue-Plus】学习笔记 11 - 集成 Sa-Token 实现登录认证流程(Sa-Token 源码)](https://blog.csdn.net/Michelle_Zhong/article/details/122480703) (2022-01-13) + - [[ 掘金 ] Springboot插件集成(三)-权限认证插件sa-token](https://juejin.cn/post/7051872914458542093) (2022-1-11) +- [[ CSDN ] Sa-token简单介绍和基本使用](https://blog.csdn.net/weixin_43967582/article/details/122075950) (2021-12-21) + +- [[ CSDN ] sa-token使用(源码解析 + 万字)](https://blog.csdn.net/weixin_39570751/article/details/121291274) (2021-11-12) + - [[ 公众号 ] 还在用Spring Security?推荐你一款使用简单、功能强大的权限认证框架](https://mp.weixin.qq.com/s/L2KOgwJcXCxrSAV8bPJsJQ) (2021-10-8) -- [[ 公众号 ] Spring Security太复杂?试试这个轻量、强大、优雅的权限认证框架!](https://mp.weixin.qq.com/s/BWziNxRZH29F2v4Tmb5meA) +- [[ 公众号 ] Spring Security太复杂?试试这个轻量、强大、优雅的权限认证框架!](https://mp.weixin.qq.com/s/BWziNxRZH29F2v4Tmb5meA) (2021-09-22) -- [[ 掘金 ] Sa-Token之注解鉴权:优雅的将鉴权与业务代码分离!](https://juejin.cn/post/7007102435705487396) (2021-9-13) +- [[ 博客园 ] Sa-Token之注解鉴权:优雅的将鉴权与业务代码分离!](https://www.cnblogs.com/shengzhang/p/15260818.html) (2021-9-13) - [[ 掘金 ] 开箱即用!看看人家的微服务权限解决方案,那叫一个优雅!](https://juejin.cn/post/7003141949259513887) (2021-9-2) @@ -35,7 +61,7 @@ - [[ 掘金 ] 史上功能最全的 Java 权限认证框架!](https://juejin.cn/post/6986174013647093773) (2021-7-18) -- [[ 掘金 ] 一个项目搞定Java权限认证框架,二十多个特性开箱即用](https://juejin.cn/post/6985077113288130574) (2021-7-15) +- [[ 知乎 ] 一个项目搞定Java权限认证框架,二十多个特性开箱即用](https://zhuanlan.zhihu.com/p/390030149) (2021-7-15) - [[ 掘金 ] 从零搭建开发脚手架 集成认证授权 sa-token(尝鲜)](https://juejin.cn/post/6950163768533843999) (2021-4-12) From ccdcf85f5012e2032532117599a8355aabecaf40 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 19 Jun 2022 06:08:50 +0800 Subject: [PATCH 027/144] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=A1=88=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/blog.md | 2 +- sa-token-doc/index.html | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sa-token-doc/doc/more/blog.md b/sa-token-doc/doc/more/blog.md index df6235bd..5051be33 100644 --- a/sa-token-doc/doc/more/blog.md +++ b/sa-token-doc/doc/more/blog.md @@ -1,7 +1,7 @@ # 框架博客 > 此页面收集 Sa-Token 相关技术文章,欢迎大家投稿(不限平台), -> 直接提交 [pr](https://gitee.com/dromara/sa-token/tree/dev/sa-token-doc/doc/more/blog.md) 即可(按照发表日期倒叙)。 +> 直接提交 [轻量级pr](https://gitee.com/dromara/sa-token/tree/dev/sa-token-doc/doc/more/blog.md) 即可(按照发表日期倒叙)。 --- diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 8988d9ae..ce1c90f7 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -273,6 +273,9 @@ + + + @@ -282,12 +285,12 @@ + + + - - - From 67969564fd7f9244510d53a2ee95f531fb054bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=94=E6=98=8E?= <2393584716@qq.com> Date: Tue, 21 Jun 2022 10:48:55 +0000 Subject: [PATCH 028/144] update sa-token-doc/doc/more/link.md. --- sa-token-doc/doc/more/link.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index bf177a70..d5bf2940 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -72,6 +72,9 @@ - [[ magic-boot ]](https://gitee.com/ssssssss-team/magic-boot):基于 magic-api + Sa-Token 搭建的快速开发平台,可以实现在浏览器编写Vue代码,既改即生效 +- [[ fhs-framework ]](https://gitee.com/fhs-opensource/fhs-framework):基于Springboot+Springcloud + Mybatis Plus + sa-token+ vue + elementui 的快速开发平台(低代码开发平台),本框架永远免费,永久全开源 + + From 6e1df178a35f62941e5f59cbdc9ae1b2c1723d72 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 28 Jun 2022 01:07:34 +0800 Subject: [PATCH 029/144] =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=9A=E5=9C=A8SpringBoot=E7=8E=AF=E5=A2=83=E9=9B=86?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/start/example.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/sa-token-doc/doc/start/example.md b/sa-token-doc/doc/start/example.md index 35cb594b..d1dce1ac 100644 --- a/sa-token-doc/doc/start/example.md +++ b/sa-token-doc/doc/start/example.md @@ -1,12 +1,14 @@ # SpringBoot 集成 Sa-Token 示例 -本篇将带你从零开始集成Sa-Token,从而让你快速熟悉Sa-Token的使用姿势
-整合示例在官方仓库的`/sa-token-demo/sa-token-demo-springboot`文件夹下,如遇到难点可结合源码进行测试学习 +本篇带你从零开始集成 Sa-Token,从而快速熟悉框架的使用姿势。 + +整合示例地址: [/sa-token-demo/sa-token-demo-springboot](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-springboot), +如遇到难点可结合示例源码进行学习测试。 --- ### 1、创建项目 -在IDE中新建一个SpringBoot项目,例如:`sa-token-demo-springboot`(不会的同学请自行百度或者参考:[SpringBoot-Pure](https://gitee.com/click33/springboot-pure)) +在 IDE 中新建一个 SpringBoot 项目,例如:`sa-token-demo-springboot`(不会的同学请自行百度或者参考:[SpringBoot-Pure](https://gitee.com/click33/springboot-pure)) ### 2、添加依赖 @@ -23,7 +25,7 @@ ### 3、设置配置文件 -你可以**零配置启动项目** ,但同时你也可以在`application.yml`中增加如下配置,定制性使用框架: +你可以**零配置启动项目** ,但同时你也可以在 `application.yml` 中增加如下配置,定制性使用框架: ``` java server: @@ -32,11 +34,11 @@ server: # Sa-Token配置 sa-token: - # token名称 (同时也是cookie名称) + # token 名称 (同时也是cookie名称) token-name: satoken - # token有效期,单位s 默认30天, -1代表永不过期 + # token 有效期,单位s 默认30天, -1代表永不过期 timeout: 2592000 - # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 + # token 临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 activity-timeout: -1 # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) is-concurrent: true @@ -48,12 +50,12 @@ sa-token: is-log: false ``` -如果你习惯于 `application.properties` 类型的配置文件,那也很好办:
+如果你习惯于 `application.properties` 类型配置文件,那也很好办:
百度: [springboot properties与yml 配置文件的区别](https://www.baidu.com/s?ie=UTF-8&wd=springboot%20properties%E4%B8%8Eyml%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB) ### 4、创建启动类 -在项目中新建包 `com.pj` ,在此包内新建主类 `SaTokenDemoApplication.java`,输入以下代码: +在项目中新建包 `com.pj` ,在此包内新建主类 `SaTokenDemoApplication.java`,复制以下代码: ``` java @SpringBootApplication @@ -105,7 +107,7 @@ public class UserController { ### 详细了解 -通过这个示例,你已经对Sa-Token有了初步的了解,那么现在开始详细了解一下它都有哪些 [能力](/use/login-auth) 吧 +通过这个示例,你已经对 Sa-Token 有了初步的了解,那么现在开始详细了解一下它都有哪些吧:[登录认证](/use/login-auth) From fcd2ca7f8d09de8910e7db0e42cd341eaa3c3ce6 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 29 Jun 2022 07:03:45 +0800 Subject: [PATCH 030/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= =?UTF-8?q?=EF=BC=9A=E7=99=BB=E5=BD=95=E8=AE=A4=E8=AF=81=E3=80=81=E6=9D=83?= =?UTF-8?q?=E9=99=90=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/_sidebar.md | 4 +- sa-token-doc/doc/start/download.md | 2 +- sa-token-doc/doc/start/example.md | 3 +- sa-token-doc/doc/start/webflux-example.md | 12 +-- sa-token-doc/doc/use/jur-auth.md | 81 +++++++++++++-------- sa-token-doc/doc/use/login-auth.md | 89 ++++++++++++++++++----- 6 files changed, 130 insertions(+), 61 deletions(-) diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 7305cc64..3ff13264 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -3,8 +3,8 @@ - **开始** - [介绍](/) - [引入](/start/download) - - [在SpringBoot环境集成](/start/example) - - [在WebFlux环境集成](/start/webflux-example) + - [在 SpringBoot 环境集成](/start/example) + - [在 WebFlux 环境集成](/start/webflux-example) - **基础** - [登录认证](/use/login-auth) diff --git a/sa-token-doc/doc/start/download.md b/sa-token-doc/doc/start/download.md index be0ec82b..35d3a10e 100644 --- a/sa-token-doc/doc/start/download.md +++ b/sa-token-doc/doc/start/download.md @@ -195,7 +195,7 @@ implementation 'cn.dev33:sa-token-core:${sa.top.version}' ## jar包下载 [点击下载:sa-token-1.6.0.jar](https://oss.dev33.cn/sa-token/sa-token-1.6.0.jar) -(注意:当前仅提供`v1.6.0`版本jar包下载,更多版本请前往maven中央仓库获取,[直达链接](https://search.maven.org/search?q=sa-token)) +注:当前仅提供 `v1.6.0` 版本jar包下载,更多版本请前往 maven 中央仓库获取,[直达链接](https://search.maven.org/search?q=sa-token) diff --git a/sa-token-doc/doc/start/example.md b/sa-token-doc/doc/start/example.md index d1dce1ac..b2430014 100644 --- a/sa-token-doc/doc/start/example.md +++ b/sa-token-doc/doc/start/example.md @@ -2,8 +2,7 @@ 本篇带你从零开始集成 Sa-Token,从而快速熟悉框架的使用姿势。 -整合示例地址: [/sa-token-demo/sa-token-demo-springboot](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-springboot), -如遇到难点可结合示例源码进行学习测试。 +整合示例在官方仓库的`/sa-token-demo/sa-token-demo-springboot`文件夹下,如遇到难点可结合源码进行学习测试。 --- diff --git a/sa-token-doc/doc/start/webflux-example.md b/sa-token-doc/doc/start/webflux-example.md index 6af65459..7ac19e56 100644 --- a/sa-token-doc/doc/start/webflux-example.md +++ b/sa-token-doc/doc/start/webflux-example.md @@ -1,16 +1,16 @@ # Spring WebFlux 集成 Sa-Token 示例 **Reactor** 是一种非阻塞的响应式模型,本篇将以 **WebFlux** 为例,展示 Sa-Token 与 Reactor 响应式模型框架相整合的示例, -**你可以用同样方式去对接其它Reactor模型框架(Netty、ShenYu、SpringCloud Gateway等)** +**你可以用同样方式去对接其它 Reactor 模型框架(Netty、ShenYu、SpringCloud Gateway等)** 整合示例在官方仓库的`/sa-token-demo/sa-token-demo-webflux`文件夹下,如遇到难点可结合源码进行测试学习 -!> WebFlux常用于微服务网关架构中,如果您的应用基于单体架构且非 Reactor 模型,可以先跳过本章 +!> WebFlux 常用于微服务网关架构中,如果您的应用基于单体架构且非 Reactor 模型,可以先跳过本章 --- ### 1、创建项目 -在IDE中新建一个SpringBoot项目,例如:`sa-token-demo-webflux`(不会的同学请自行百度或者参考github示例) +在 IDE 中新建一个 SpringBoot 项目,例如:`sa-token-demo-webflux` ### 2、添加依赖 @@ -40,7 +40,7 @@ public class SaTokenDemoApplication { ``` ### 4、创建全局过滤器 -新建`SaTokenConfigure.java`,注册Sa-Token的全局过滤器 +新建`SaTokenConfigure.java`,注册 Sa-Token 的全局过滤器 ``` java /** * [Sa-Token 权限认证] 全局配置类 @@ -71,7 +71,7 @@ public class SaTokenConfigure { } } ``` -?> 你只需要按照此格式复制代码即可,有关过滤器的详细用法,会在之后的章节详细介绍 +你只需要按照此格式复制代码即可,有关过滤器的详细用法,会在之后的章节详细介绍。 ### 5、创建测试Controller @@ -108,7 +108,7 @@ public class UserController { ![运行结果](https://oss.dev33.cn/sa-token/doc/test-is-login.png) -**注意事项** +**注意事项:** 更多使用示例请参考官方仓库demo diff --git a/sa-token-doc/doc/use/jur-auth.md b/sa-token-doc/doc/use/jur-auth.md index dbc7d760..c02c8913 100644 --- a/sa-token-doc/doc/use/jur-auth.md +++ b/sa-token-doc/doc/use/jur-auth.md @@ -2,36 +2,31 @@ --- -### 核心思想 +### 设计思路 -所谓权限认证,认证的核心就是一个账号是否拥有一个权限码
-有,就让你通过。没有?那么禁止访问! +所谓权限认证,核心逻辑就是判断一个账号是否拥有指定权限:
+- 有,就让你通过。 +- 没有?那么禁止访问! -再往底了说,就是每个账号都会拥有一个权限码集合,我来校验这个集合中是否包含指定的权限码
-例如:当前账号拥有权限码集合:`["user-add", "user-delete", "user-get"]`,这时候我来校验权限 `"user-update"`,则其结果就是:**验证失败,禁止访问**
+深入到底层数据中,就是每个账号都会拥有一个权限码集合,框架来校验这个集合中是否包含指定的权限码。 + +例如:当前账号拥有权限码集合 `["user-add", "user-delete", "user-get"]`,这时候我来校验权限 `"user-update"`,则其结果就是:**验证失败,禁止访问**。
-所以现在问题的核心就是: -1. 如何获取一个账号所拥有的的权限码集合 -2. 本次操作需要验证的权限码是哪个 +所以现在问题的核心就是: +1. 如何获取一个账号所拥有的的权限码集合? +2. 本次操作需要验证的权限码是哪个? ### 获取当前账号权限码集合 -因为每个项目的需求不同,其权限设计也千变万化,因此【获取当前账号权限码集合】这一操作不可能内置到框架中, -所以 Sa-Token 将此操作以接口的方式暴露给你,以方便的你根据自己的业务逻辑进行重写 +因为每个项目的需求不同,其权限设计也千变万化,因此 [ 获取当前账号权限码集合 ] 这一操作不可能内置到框架中, +所以 Sa-Token 将此操作以接口的方式暴露给你,以方便你根据自己的业务逻辑进行重写。 -你需要做的就是新建一个类,实现`StpInterface`接口,例如以下代码: +你需要做的就是新建一个类,实现 `StpInterface`接口,例如以下代码: ``` java -package com.pj.satoken; - -import java.util.ArrayList; -import java.util.List; -import org.springframework.stereotype.Component; -import cn.dev33.satoken.stp.StpInterface; - /** * 自定义权限验证接口扩展 */ @@ -69,6 +64,10 @@ public class StpInterfaceImpl implements StpInterface { } ``` +**参数解释:** +- loginId:账号id,即你在调用 `StpUtil.login(id)` 时写入的标识值。 +- loginType:账号体系标识,此处可以暂时忽略,在 [ 多账户认证 ] 章节下会对这个概念做详细的解释。 + 可参考代码:[码云:StpInterfaceImpl.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/StpInterfaceImpl.java) @@ -76,7 +75,10 @@ public class StpInterfaceImpl implements StpInterface { ### 权限认证 然后就可以用以下api来鉴权了 -``` java +``` java +// 获取:当前账号所拥有的权限集合 +StpUtil.getPermissionList(); + // 判断:当前账号是否含有指定权限, 返回true或false StpUtil.hasPermission("user-update"); @@ -87,7 +89,7 @@ StpUtil.checkPermission("user-update"); StpUtil.checkPermissionAnd("user-update", "user-delete"); // 校验:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可] -StpUtil.checkPermissionOr("user-update", "user-delete"); +StpUtil.checkPermissionOr("user-update", "user-delete"); ``` 扩展:`NotPermissionException` 对象可通过 `getLoginType()` 方法获取具体是哪个 `StpLogic` 抛出的异常 @@ -97,6 +99,9 @@ StpUtil.checkPermissionOr("user-update", "user-delete"); 在Sa-Token中,角色和权限可以独立验证 ``` java +// 获取:当前账号所拥有的角色集合 +StpUtil.getRoleList(); + // 判断:当前账号是否拥有指定角色, 返回true或false StpUtil.hasRole("super-admin"); @@ -115,13 +120,27 @@ StpUtil.checkRoleOr("super-admin", "shop-admin"); ### 拦截全局异常 -有同学要问,鉴权失败,抛出异常,然后呢?要把异常显示给用户看吗?**当然不可以!**
+有同学要问,鉴权失败,抛出异常,然后呢?要把异常显示给用户看吗?**当然不可以!** + 你可以创建一个全局异常拦截器,统一返回给前端的格式,参考: -[码云:GlobalException.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/current/GlobalException.java) + +``` java +@RestControllerAdvice +public class GlobalExceptionHandler { + // 全局异常拦截 + @ExceptionHandler + public SaResult handlerException(Exception e) { + e.printStackTrace(); + return SaResult.error(e.getMessage()); + } +} +``` + +可参考:[码云:GlobalException.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/current/GlobalException.java) ### 权限通配符 -Sa-Token允许你根据通配符指定泛权限,例如当一个账号拥有`user*`的权限时,`user-add`、`user-delete`、`user-update`都将匹配通过 +Sa-Token允许你根据通配符指定**泛权限**,例如当一个账号拥有`user*`的权限时,`user-add`、`user-delete`、`user-update`都将匹配通过 ``` java // 当拥有 user* 权限时 @@ -140,26 +159,26 @@ StpUtil.hasPermission("index.css"); // false StpUtil.hasPermission("index.html"); // false ``` -上帝权限:当一个账号拥有 `"*"` 权限时,他可以验证通过任何权限码 (角色认证同理) +!> 上帝权限:当一个账号拥有 `"*"` 权限时,他可以验证通过任何权限码 (角色认证同理) ### 如何把权限精确到按钮级? -权限精确到按钮级的意思就是指:**权限范围可以控制到页面上的每一个按钮是否显示** +权限精确到按钮级的意思就是指:**权限范围可以控制到页面上的每一个按钮是否显示**。 -思路:如此精确的范围控制只依赖后端已经难以完成,此时需要前端进行一定的逻辑判断 +思路:如此精确的范围控制只依赖后端已经难以完成,此时需要前端进行一定的逻辑判断。 如果是前后端一体项目,可以参考:[Thymeleaf 标签方言](/plugin/thymeleaf-extend),如果是前后端分离项目,则: -1. 在登录时,把当前账号拥有的所有权限码一次性返回给前端 -2. 前端将权限码集合保存在`localStorage`或其它全局状态管理对象中 -3. 在需要权限控制的按钮上,使用js进行逻辑判断,例如在`vue`框架中我们可以使用如下写法: +1. 在登录时,把当前账号拥有的所有权限码一次性返回给前端。 +2. 前端将权限码集合保存在`localStorage`或其它全局状态管理对象中。 +3. 在需要权限控制的按钮上,使用 js 进行逻辑判断,例如在`Vue`框架中我们可以使用如下写法: ``` js ``` -其中:`arr`是当前用户拥有的权限码数组,`user:delete`是显示按钮需要拥有的权限码,`删除按钮`是用户拥有权限码才可以看到的内容 +其中:`arr`是当前用户拥有的权限码数组,`user:delete`是显示按钮需要拥有的权限码,`删除按钮`是用户拥有权限码才可以看到的内容。 -注意:以上写法只为提供一个参考示例,不同框架有不同写法,开发者可根据项目技术栈灵活封装进行调用 +注意:以上写法只为提供一个参考示例,不同框架有不同写法,大家可根据项目技术栈灵活封装进行调用。 ### 前端有了鉴权后端还需要鉴权吗? diff --git a/sa-token-doc/doc/use/login-auth.md b/sa-token-doc/doc/use/login-auth.md index a300a780..e67c636a 100644 --- a/sa-token-doc/doc/use/login-auth.md +++ b/sa-token-doc/doc/use/login-auth.md @@ -2,23 +2,74 @@ --- -### 核心思想 +### 设计思路 -所谓登录认证,说白了就是限制某些API接口必须登录后才能访问(例:查询我的账号资料)
-那么如何判断一个会话是否登录?框架会在登录成功后给你做个标记,每次登录认证时校验这个标记,有标记者视为已登录,无标记者视为未登录! +对于一些登录之后才能访问的接口(例如:查询我的账号资料),我们通常的做法是增加一层接口校验: + +- 如果校验通过,则:正常返回数据。 +- 如果校验未通过,则:抛出异常,告知其需要先进行登录。 + +那么,判断会话是否登录的依据是什么?我们先来简单分析一下登录访问流程: + +1. 用户提交 `name` + `password` 参数,调用登录接口。 +2. 登录成功,返回这个用户的 Token 会话凭证。 +3. 用户后续的每次请求,都携带上这个 Token。 +4. 服务器根据 Token 判断此会话是否登录成功。 + +所谓登录认证,指的就是服务器校验账号密码,为用户颁发 Token 会话凭证的过程,这个 Token 也是我们后续通过接口校验的关键所在。 ### 登录与注销 -根据以上思路,我们很容易想到以下api: +根据以上思路,我们需要一个会话登录的函数: ``` java -// 标记当前会话登录的账号id -// 建议的参数类型:long | int | String, 不可以传入复杂类型,如:User、Admin等等 +// 会话登录:参数填写要登录的账号id,建议的数据类型:long | int | String, 不可以传入复杂类型,如:User、Admin 等等 StpUtil.login(Object id); +``` +只此一句代码,便可以使会话登录成功,实际上,Sa-Token 在背后做了大量的工作,包括但不限于: + +1. 检查此账号是否已被封禁 +2. 检查此账号是否之前已有登录 +3. 为账号生成 `Token` 凭证与 `Session` 会话 +4. 通知全局侦听器,xx 账号登录成功 +5. 将 `Token` 注入到请求上下文 +6. 等等其它工作…… + +你暂时不需要完整的了解整个登录过程,你只需要记住关键一点:`Sa-Token 为这个账号创建了一个Token凭证,且通过 Cookie 上下文返回给了前端`。 + +所以一般情况下,我们的登录接口代码,会大致类似如下: + +``` java +// 会话登录接口 +@RequestMapping("doLogin") +public SaResult doLogin(String name, String pwd) { + // 第一步:比对前端提交的账号名称、密码 + if("zhang".equals(name) && "123456".equals(pwd)) { + // 第二步:根据账号id,进行登录 + StpUtil.login(10001); + return SaResult.ok("登录成功"); + } + return SaResult.error("登录失败"); +} +``` + +如果你对以上代码阅读没有压力,你可能会注意到略显奇怪的一点:此处仅仅做了会话登录,但并没有主动向前端返回 Token 信息。 +是因为不需要吗?严格来讲是需要的,只不过 `StpUtil.login(id)` 方法利用了 Cookie 自动注入的特性,省略了你手写返回 Token 的代码。 + +如果你对 Cookie 功能还不太了解,也不用担心,我们会在之后的 [ 前后端分离 ] 章节中详细的阐述 Cookie 功能,现在你只需要了解最基本的两点: + +- Cookie 可以从后端控制往浏览器中写入 Token 值。 +- Cookie 会在每次请求时自动提交 Token 值。 + +因此,在 Cookie 功能的加持下,我们可以仅靠 `StpUtil.login(id)` 一句代码就完成登录认证。 + +除了登录方法,我们还需要: + +``` java // 当前会话注销登录 StpUtil.logout(); @@ -26,12 +77,11 @@ StpUtil.logout(); StpUtil.isLogin(); // 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException` -StpUtil.checkLogin() +StpUtil.checkLogin(); ``` -##### `NotLoginException`异常对象扩展: -1. 通过 `getLoginType()` 方法获取具体是哪个 `StpLogic` 抛出的异常
-2. 通过 `getType()` 方法获取具体的场景值,详细参考章节:[未登录场景值](/fun/not-login-scene) +异常 `NotLoginException` 代表当前会话暂未登录,可能的原因有很多: +前端没有提交 Token、前端提交的 Token 是无效的、前端提交的 Token 已经过期 …… 等等,可参照此篇:[未登录场景值](/fun/not-login-scene),了解如何获取未登录的场景值。 ### 会话查询 @@ -54,29 +104,32 @@ StpUtil.getLoginId(T defaultValue); ``` -### 其它API +### Token 查询 ``` java -// 获取指定token对应的账号id,如果未登录,则返回 null -StpUtil.getLoginIdByToken(String tokenValue); +// 获取当前会话的token值 +StpUtil.getTokenValue(); // 获取当前`StpLogic`的token名称 StpUtil.getTokenName(); -// 获取当前会话的token值 -StpUtil.getTokenValue(); +// 获取指定token对应的账号id,如果未登录,则返回 null +StpUtil.getLoginIdByToken(String tokenValue); + +// 获取当前会话剩余有效期(单位:s,返回-1代表永久有效) +StpUtil.getTokenTimeout(); // 获取当前会话的token信息参数 StpUtil.getTokenInfo(); ``` +有关`TokenInfo`参数详解,请参考:[TokenInfo参数详解](/fun/token-info) + ### 来个小测试,加深一下理解 新建 `LoginController`,复制以下代码 ``` java /** * 登录测试 - * @author kong - * */ @RestController @RequestMapping("/acc/") @@ -115,7 +168,5 @@ public class LoginController { } ``` -> 有关`TokenInfo`参数详解,请参考:[TokenInfo参数详解](/fun/token-info) - From 48877773157f41d1b16c52022103d2a8a1c3364d Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 29 Jun 2022 08:14:58 +0800 Subject: [PATCH 031/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= =?UTF-8?q?=EF=BC=9Asession=E4=BC=9A=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/_sidebar.md | 2 +- sa-token-doc/doc/use/at-check.md | 26 +++---- sa-token-doc/doc/use/kick.md | 2 +- sa-token-doc/doc/use/route-check.md | 16 +++-- sa-token-doc/doc/use/session.md | 105 +++++++++++----------------- 5 files changed, 64 insertions(+), 87 deletions(-) diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 3ff13264..5b50157f 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -10,7 +10,7 @@ - [登录认证](/use/login-auth) - [权限认证](/use/jur-auth) - [踢人下线](/use/kick) - - [注解式鉴权](/use/at-check) + - [注解鉴权](/use/at-check) - [路由拦截鉴权](/use/route-check) - [Session会话](/use/session) - [框架配置](/use/config) diff --git a/sa-token-doc/doc/use/at-check.md b/sa-token-doc/doc/use/at-check.md index 2287102a..9daa9cab 100644 --- a/sa-token-doc/doc/use/at-check.md +++ b/sa-token-doc/doc/use/at-check.md @@ -1,25 +1,25 @@ -# 注解式鉴权 +# 注解鉴权 --- 有同学表示:尽管使用代码鉴权非常方便,但是我仍希望把鉴权逻辑和业务逻辑分离开来,我可以使用注解鉴权吗?当然可以!
注解鉴权 —— 优雅的将鉴权与业务代码分离! -- `@SaCheckLogin`: 登录认证 —— 只有登录之后才能进入该方法 -- `@SaCheckRole("admin")`: 角色认证 —— 必须具有指定角色标识才能进入该方法 -- `@SaCheckPermission("user:add")`: 权限认证 —— 必须具有指定权限才能进入该方法 -- `@SaCheckSafe`: 二级认证校验 —— 必须二级认证之后才能进入该方法 -- `@SaCheckBasic`: HttpBasic认证 —— 只有通过 Basic 认证后才能进入该方法 +- `@SaCheckLogin`: 登录认证 —— 只有登录之后才能进入该方法。 +- `@SaCheckRole("admin")`: 角色认证 —— 必须具有指定角色标识才能进入该方法。 +- `@SaCheckPermission("user:add")`: 权限认证 —— 必须具有指定权限才能进入该方法。 +- `@SaCheckSafe`: 二级认证校验 —— 必须二级认证之后才能进入该方法。 +- `@SaCheckBasic`: HttpBasic认证 —— 只有通过 Basic 认证后才能进入该方法。 -Sa-Token使用全局拦截器完成注解鉴权功能,为了不为项目带来不必要的性能负担,拦截器默认处于关闭状态
-因此,为了使用注解鉴权,你必须手动将Sa-Token的全局拦截器注册到你项目中 +Sa-Token 使用全局拦截器完成注解鉴权功能,为了不为项目带来不必要的性能负担,拦截器默认处于关闭状态
+因此,为了使用注解鉴权,**你必须手动将 Sa-Token 的全局拦截器注册到你项目中** ### 1、注册拦截器 -以`SpringBoot2.0`为例, 新建配置类`SaTokenConfigure.java` +以`SpringBoot2.0`为例,新建配置类`SaTokenConfigure.java` ``` java @Configuration @@ -38,7 +38,7 @@ public class SaTokenConfigure implements WebMvcConfigurer { ### 2、使用注解鉴权 -然后我们就可以愉快的使用注解鉴权: +然后我们就可以愉快的使用注解鉴权了: ``` java // 登录认证:只有登录之后才能进入该方法 @@ -92,12 +92,12 @@ public SaResult atJurOr() { ``` mode有两种取值: -- `SaMode.AND`, 标注一组权限,会话必须全部具有才可通过校验 -- `SaMode.OR`, 标注一组权限,会话只要具有其一即可通过校验 +- `SaMode.AND`, 标注一组权限,会话必须全部具有才可通过校验。 +- `SaMode.OR`, 标注一组权限,会话只要具有其一即可通过校验。 ### 4、角色权限双重 “or校验” -假设有以下业务场景:一个接口在具体权限 `user-add` 或角色 `admin` 时可以调通。怎么写? +假设有以下业务场景:一个接口在具有权限 `user-add` 或角色 `admin` 时可以调通。怎么写? ``` java // 注解式鉴权:只要具有其中一个权限即可通过校验 diff --git a/sa-token-doc/doc/use/kick.md b/sa-token-doc/doc/use/kick.md index d5189bcd..5b4a8cd5 100644 --- a/sa-token-doc/doc/use/kick.md +++ b/sa-token-doc/doc/use/kick.md @@ -1,5 +1,5 @@ # 踢人下线 -所谓踢人下线,核心操作就是找到其指定`loginId`对应的`token`,并设置其失效 +所谓踢人下线,核心操作就是找到指定 `loginId` 对应的 `Token`,并设置其失效。 ![踢下线](https://oss.dev33.cn/sa-token/doc/kickout.png) diff --git a/sa-token-doc/doc/use/route-check.md b/sa-token-doc/doc/use/route-check.md index e81c006a..a1ab0996 100644 --- a/sa-token-doc/doc/use/route-check.md +++ b/sa-token-doc/doc/use/route-check.md @@ -2,9 +2,10 @@ --- 假设我们有如下需求: -> 项目中所有接口均需要登录认证,只有'登录接口'本身对外开放 +> 项目中所有接口均需要登录认证,只有 '登录接口' 本身对外开放 + +我们怎么实现呢?给每个接口加上鉴权注解?手写全局拦截器?似乎都不是非常方便。 -我们怎么实现呢?给每个接口加上鉴权注解?手写全局拦截器?似乎都不是非常方便。
在这个需求中我们真正需要的是一种基于路由拦截的鉴权模式, 那么在Sa-Token怎么实现路由拦截鉴权呢? @@ -17,26 +18,27 @@ public class SaTokenConfigure implements WebMvcConfigurer { // 注册拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { - // 注册Sa-Token的路由拦截器 + // 注册 Sa-Token 的路由拦截器 registry.addInterceptor(new SaRouteInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/user/doLogin"); } } ``` -以上代码,我们注册了一个登录认证拦截器,并且排除了`/user/doLogin`接口用来开放登录(除了`/user/doLogin`以外的所有接口都需要登录才能访问)
-那么我们如何进行权限认证拦截呢,且往下看 +以上代码,我们注册了一个登录认证拦截器,并且排除了`/user/doLogin`接口用来开放登录(除了`/user/doLogin`以外的所有接口都需要登录才能访问)。 ### 2、校验函数详解 -你可以使用函数式编程自定义认证规则,例如: +自定义认证规则:`new SaRouteInterceptor()` 是最简单的无参构造写法,代表只进行默认的登录校验功能。 + +我们可以往构造函数塞一个 lambda 表达式,来自定义认证规则,例如: ``` java @Configuration public class SaTokenConfigure implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { - // 注册路由拦截器,自定义认证规则 + // 注册 Sa-Token 的路由拦截器,自定义认证规则 registry.addInterceptor(new SaRouteInterceptor((req, res, handler)->{ // 根据路由划分模块,不同模块不同鉴权 SaRouter.match("/user/**", r -> StpUtil.checkPermission("user")); diff --git a/sa-token-doc/doc/use/session.md b/sa-token-doc/doc/use/session.md index b715b00c..f5af77fb 100644 --- a/sa-token-doc/doc/use/session.md +++ b/sa-token-doc/doc/use/session.md @@ -19,7 +19,7 @@ SysUser user = (SysUser) StpUtil.getSession().get("user"); - `Token-Session`: 指的是框架为每个 token 分配的 Session - `Custom-Session`: 指的是以一个 特定的值 作为SessionId,来分配的 Session -> 有关User-Session与Token-Session的详细区别,请参考:[Session模型详解](/fun/session-model) +> 有关User-Session与Token-Session的详细区别,可参考:[Session模型详解](/fun/session-model) ### User-Session @@ -72,50 +72,8 @@ SaSessionCustomUtil.deleteSessionById("goods-10001"); ``` -### Session相关操作 -那么获取到的`SaSession`具体有哪些方法可供操作? -``` java -// 返回此Session的id -session.getId(); +### 在 Session 上存取值 -// 返回此Session的创建时间 (时间戳) -session.getCreateTime(); - -// 在Session上获取一个值 -session.getAttribute('name'); - -// 在Session上获取一个值,并指定取不到值时返回的默认值 -session.getAttribute('name', 'zhang'); - -// 在Session上写入一个值 -session.setAttribute('name', 'zhang'); - -// 在Session上移除一个值 -session.removeAttribute('name'); - -// 清空此Session的所有值 -session.clearAttribute(); - -// 获取此Session是否含有指定key (返回true或false) -session.containsAttribute('name'); - -// 获取此Session会话上所有key (返回Set) -session.attributeKeys(); - -// 返回此Session会话上的底层数据对象(如果更新map里的值,请调用session.update()方法避免产生脏数据) -session.getDataMap(); - -// 将这个Session从持久库更新一下 -session.update(); - -// 注销此Session会话 (从持久库删除此Session) -session.logout(); -``` - - -### 类型转换API -由于Session存取值默认的类型都是Object,因此我们通常会写很多不必要类型转换代码
-为了简化操作,Sa-Token自`v1.15.0`封装了存取值API的类型转换,你可以非常方便的调用以下方法: ``` java // 写值 session.set("name", "zhang"); @@ -129,29 +87,46 @@ session.get("name"); // 取值 (指定默认值) session.get("name", ""); -// 取值 (转String类型) -session.getString("name"); +// ---------- 数据类型转换: ---------- +session.getInt("age"); // 取值 (转int类型) +session.getLong("age"); // 取值 (转long类型) +session.getString("name"); // 取值 (转String类型) +session.getDouble("result"); // 取值 (转double类型) +session.getFloat("result"); // 取值 (转float类型) +session.getModel("key", Student.class); // 取值 (指定转换类型) +session.getModel("key", Student.class, ); // 取值 (指定转换类型, 并指定值为Null时返回的默认值) -// 取值 (转int类型) -session.getInt("age"); - -// 取值 (转long类型) -session.getLong("age"); - -// 取值 (转double类型) -session.getDouble("result"); - -// 取值 (转float类型) -session.getFloat("result"); - -// 取值 (指定转换类型) -session.getModel("key", Student.class); - -// 取值 (指定转换类型, 并指定值为Null时返回的默认值) -session.getModel("key", Student.class, ); - -// 是否含有某个key +// 是否含有某个key (返回true或false) session.has("key"); + +// 删值 +session.delete('name'); + +// 清空所有值 +session.clear(); + +// 获取此 Session 的所有key (返回Set) +session.keys(); +``` + + +### 其它操作 + +``` java +// 返回此 Session 的id +session.getId(); + +// 返回此 Session 的创建时间 (时间戳) +session.getCreateTime(); + +// 返回此 Session 会话上的底层数据对象(如果更新map里的值,请调用session.update()方法避免产生脏数据) +session.getDataMap(); + +// 将这个 Session 从持久库更新一下 +session.update(); + +// 注销此 Session 会话 (从持久库删除此Session) +session.logout(); ``` From 013c08187db7b03f83f7a2fd99e01b35f923bee5 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 30 Jun 2022 09:35:56 +0800 Subject: [PATCH 032/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= =?UTF-8?q?=EF=BC=9A=E6=A1=86=E6=9E=B6=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/use/config.md | 62 ++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index 0f736806..7144d9e6 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -72,20 +72,23 @@ PS:两者的区别在于:**`模式1会覆盖yml中的配置,模式2会与y --- ### 所有可配置项 + +你不必立刻掌握整个表格,只需要在用到某个功能时再详细查阅它即可 + | 参数名称 | 类型 | 默认值 | 说明 | | :-------- | :-------- | :-------- | :-------- | -| tokenName | String | satoken | token名称 (同时也是cookie名称) | -| timeout | long | 2592000 | token有效期,单位/秒 默认30天,-1代表永久有效 [参考:token有效期详解](/fun/token-timeout) | -| activityTimeout | long | -1 | token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒, 默认-1 代表不限制 (例如可以设置为1800代表30分钟内无操作就过期) [参考:token有效期详解](/fun/token-timeout) | -| isConcurrent | Boolean | true | 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) | -| isShare | Boolean | true | 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) | -| maxLoginCount | int | 12 | 同一账号最大登录数量,-1代表不限 (只有在 isConcurrent=true, isShare=false 时此配置才有效) | +| tokenName | String | satoken | Token 名称 (同时也是 Cookie 名称、数据持久化前缀) | +| timeout | long | 2592000 | Token 有效期,单位/秒 默认30天,-1代表永久有效 [参考:token有效期详解](/fun/token-timeout) | +| activityTimeout | long | -1 | Token 临时有效期 (指定时间内无操作就视为token过期) 单位: 秒, 默认-1 代表不限制 (例如可以设置为1800代表30分钟内无操作就过期) [参考:token有效期详解](/fun/token-timeout) | +| isConcurrent | Boolean | true | 是否允许同一账号并发登录 (为 true 时允许一起登录,为 false 时新登录挤掉旧登录) | +| isShare | Boolean | true | 在多人登录同一账号时,是否共用一个token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) | +| maxLoginCount | int | 12 | 同一账号最大登录数量,-1代表不限 (只有在 `isConcurrent=true`, `isShare=false` 时此配置才有效),[详解](/use/config?id=maxlogincount) | | isReadBody | Boolean | true | 是否尝试从 请求体 里读取 Token | | isReadHead | Boolean | true | 是否尝试从 header 里读取 Token | -| isReadCookie | Boolean | true | 是否尝试从 cookie 里读取 Token | -| tokenStyle | String | uuid | token风格, [参考:自定义Token风格](/up/token-style) | -| dataRefreshPeriod | int | 30 | 默认dao层实现类中,每次清理过期数据间隔的时间 (单位: 秒) ,默认值30秒,设置为-1代表不启动定时清理 | -| tokenSessionCheckLogin | Boolean | true | 获取 `Token-Session` 时是否必须登录 (如果配置为true,会在每次获取 `Token-Session` 时校验是否登录) | +| isReadCookie | Boolean | true | 是否尝试从 cookie 里读取 Token,此值为 false 后,`StpUtil.login(id)` 登录时也不会再往前端注入Cookie | +| tokenStyle | String | uuid | token风格, [参考:自定义Token风格](/up/token-style) | +| dataRefreshPeriod | int | 30 | 默认数据持久组件实现类中,每次清理过期数据间隔的时间 (单位: 秒) ,默认值30秒,设置为-1代表不启动定时清理 | +| tokenSessionCheckLogin | Boolean | true | 获取 `Token-Session` 时是否必须登录 (如果配置为true,会在每次获取 `Token-Session` 时校验是否登录),[详解](/use/config?id=tokenSessionCheckLogin) | | autoRenew | Boolean | true | 是否打开自动续签 (如果此值为true, 框架会在每次直接或间接调用 `getLoginId()` 时进行一次过期检查与续签操作) | | tokenPrefix | String | null | token前缀, 例如填写 `Bearer` 实际传参 `satoken: Bearer xxxx-xxxx-xxxx-xxxx` [参考:自定义Token前缀](/up/token-prefix) | | isPrint | Boolean | true | 是否在初始化配置时打印版本字符画 | @@ -194,3 +197,42 @@ sa-token: | pastClientTokenTimeout | long | 取全局配置 | 单独配置此Client:`Past-Client-Token` 保存的时间(单位:秒) [默认取全局配置] | + +### 部分配置项详解 + +对部分配置项做一下详解 + +#### maxLoginCount + +配置含义:同一账号最大登录数量。 + +在配置 `isConcurrent=true`, `isShare=false` 时,Sa-Token 将允许同一账号并发登录,且每次登录都会产生一个新Token, +这些 Token 都会以 `TokenSign` 的形式记录在其 `User-Session` 之上,这就造成一个问题: + +随着同一账号登录的次数越来越多,TokenSign 的列表也会越来越大,极端情况下,列表长度可能达到成百上千以上,严重拖慢数据处理速度, +为此 Sa-Token 对这个 TokenSign 列表的大小设定一个上限值,也就是 `maxLoginCount`,默认值=12。 + +假设一个账号的登录数量超过 `maxLoginCount` 后,将会主动注销第一个登录的会话(先进先出),以此保证队列中的有效会话数量始终 `<= maxLoginCount` 值。 + + +#### tokenSessionCheckLogin +配置含义:获取 `Token-Session` 时是否必须登录 (如果配置为true,会在每次获取 `Token-Session` 时校验是否登录)。 + +主要用法:在调用 `StpUtil.login(id)` 登录后, + +- 调用 `StpUtil.getSession()` 可以获取这个会话的 `User-Session` 对象。 +- 调用 `StpUtil.getTokenSession()` 可以获取这个会话 `Token-Session` 对象。 + +关于两种 Session 有何区别,可以参考这篇:[Session模型详解](/fun/session-model),此处暂不赘述。 + +从设计上讲,无论会话是否已经登录,只要前端提供了Token,我们就可以找到这个 Token 的专属 `Token-Session` 对象,**这非常灵活但不安全**, +因为前端提交的 Token 可能是任意伪造的。 + +为了解决这个问题,`StpUtil.getTokenSession()` 方法在获取 `Token-Session` 时,会率先检测一下这个 Token 是否是一个有效Token: +- 如果是有效Token,正常返回 `Token-Session` 对象 +- 如果是无效Token,则 + + + + + From 81524ba3aaa19c214dc8552e853967c26ac9457c Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 30 Jun 2022 09:37:15 +0800 Subject: [PATCH 033/144] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E5=8F=8B=E8=81=94?= =?UTF-8?q?=EF=BC=9AApache-ShenYu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/index.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index ce1c90f7..db3f9771 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -328,9 +328,6 @@

友情链接

- - - From c3275aeba62eb8c85a605b502dc9b899824ccd5a Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 30 Jun 2022 10:50:41 +0800 Subject: [PATCH 034/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= =?UTF-8?q?=EF=BC=9A=E6=A1=86=E6=9E=B6=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/use/config.md | 26 +++++++++++++++++--------- sa-token-doc/index.html | 3 +++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index 7144d9e6..f04eb9bb 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -89,16 +89,15 @@ PS:两者的区别在于:**`模式1会覆盖yml中的配置,模式2会与y | tokenStyle | String | uuid | token风格, [参考:自定义Token风格](/up/token-style) | | dataRefreshPeriod | int | 30 | 默认数据持久组件实现类中,每次清理过期数据间隔的时间 (单位: 秒) ,默认值30秒,设置为-1代表不启动定时清理 | | tokenSessionCheckLogin | Boolean | true | 获取 `Token-Session` 时是否必须登录 (如果配置为true,会在每次获取 `Token-Session` 时校验是否登录),[详解](/use/config?id=tokenSessionCheckLogin) | -| autoRenew | Boolean | true | 是否打开自动续签 (如果此值为true, 框架会在每次直接或间接调用 `getLoginId()` 时进行一次过期检查与续签操作) | -| tokenPrefix | String | null | token前缀, 例如填写 `Bearer` 实际传参 `satoken: Bearer xxxx-xxxx-xxxx-xxxx` [参考:自定义Token前缀](/up/token-prefix) | +| autoRenew | Boolean | true | 是否打开自动续签 (如果此值为true, 框架会在每次直接或间接调用 `getLoginId()` 时进行一次过期检查与续签操作),[参考:token有效期详解](/fun/token-timeout) | +| tokenPrefix | String | null | token前缀,例如填写 `Bearer` 实际传参 `satoken: Bearer xxxx-xxxx-xxxx-xxxx` [参考:自定义Token前缀](/up/token-prefix) | | isPrint | Boolean | true | 是否在初始化配置时打印版本字符画 | | isLog | Boolean | false | 是否打印操作日志 | -| jwtSecretKey | String | null | jwt秘钥 (只有集成 `sa-token-temp-jwt` 模块时此参数才会生效) | -| idTokenTimeout | long | 86400 | Id-Token的有效期 (单位: 秒) | +| jwtSecretKey | String | null | jwt秘钥 (只有集成 `sa-token-temp-jwt` 模块时此参数才会生效),[参考:和 jwt 集成](/plugin/jwt-extend) | +| idTokenTimeout | long | 86400 | Id-Token的有效期 (单位: 秒),[参考:内部服务外网隔离](/micro/id-token) | | basic | String | "" | Http Basic 认证的账号和密码 [参考:Http Basic 认证](/up/basic-auth) | | currDomain | String | null | 配置当前项目的网络访问地址 | | checkIdToken | Boolean | false | 是否校验Id-Token(部分rpc插件有效) | -| sso | Object | new SaSsoConfig() | SSO 单点登录相关配置 | | cookie | Object | new SaCookieConfig() | Cookie配置对象 | Cookie相关配置: @@ -189,7 +188,7 @@ sa-token: | isImplicit | Boolean | false | 单独配置此 Client 是否打开模式:隐藏式(`Implicit`) | | isPassword | Boolean | false | 单独配置此 Client 是否打开模式:密码式(`Password`) | | isClient | Boolean | false | 单独配置此 Client 是否打开模式:凭证式(`Client Credentials`) | -| isAutoMode | Boolean | true | 是否自动判断此 Client 开放的授权模式。
此值为 true 时:四种模式(`isCode、isImplicit、isPassword、isClient`)是否生效,依靠全局设置;
此值为 false 时:四种模式(`isCode、isImplicit、isPassword、isClient`)是否生效,依靠局部配置+全局配置 | +| isAutoMode | Boolean | true | 是否自动判断此 Client 开放的授权模式。 参考:[详解](/use/config?id=isAutoMode) | | isNewRefresh | Boolean | 取全局配置 | 单独配置此Client:是否在每次 `Refresh-Token` 刷新 `Access-Token` 时,产生一个新的 Refresh-Token [ 默认取全局配置 ] | | accessTokenTimeout | long | 取全局配置 | 单独配置此Client:`Access-Token` 保存的时间(单位:秒) [默认取全局配置] | | refreshTokenTimeout | long | 取全局配置 | 单独配置此Client:`Refresh-Token` 保存的时间(单位:秒) [默认取全局配置] | @@ -218,7 +217,7 @@ sa-token: #### tokenSessionCheckLogin 配置含义:获取 `Token-Session` 时是否必须登录 (如果配置为true,会在每次获取 `Token-Session` 时校验是否登录)。 -主要用法:在调用 `StpUtil.login(id)` 登录后, +在调用 `StpUtil.login(id)` 登录后, - 调用 `StpUtil.getSession()` 可以获取这个会话的 `User-Session` 对象。 - 调用 `StpUtil.getTokenSession()` 可以获取这个会话 `Token-Session` 对象。 @@ -230,9 +229,18 @@ sa-token: 为了解决这个问题,`StpUtil.getTokenSession()` 方法在获取 `Token-Session` 时,会率先检测一下这个 Token 是否是一个有效Token: - 如果是有效Token,正常返回 `Token-Session` 对象 -- 如果是无效Token,则 - +- 如果是无效Token,则抛出异常。 + +这样就保证了伪造的 Token 是无法获取 `Token-Session` 对象的。 + +但是 —— 有的场景下我们又确实需要关闭这个校验功能,这时候就把配置项 `tokenSessionCheckLogin` 值改为 `false` 即可。 +#### isAutoMode + +配置含义:是否自动判断此 Client 开放的授权模式。 + +- 此值为 true 时:四种模式(`isCode、isImplicit、isPassword、isClient`)是否生效,依靠全局设置; +- 此值为 false 时:四种模式(`isCode、isImplicit、isPassword、isClient`)是否生效,依靠局部配置+全局配置(两个都为 true 时才打开) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index db3f9771..31ea14a1 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -370,6 +370,9 @@ + + +
From 516e52c649a4813d1aa68b2985b54f70bd485d5a Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 4 Jul 2022 11:48:29 +0800 Subject: [PATCH 035/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/up/global-filter.md | 20 ++++---- sa-token-doc/doc/up/global-listener.md | 6 +-- sa-token-doc/doc/up/integ-redis.md | 38 +++++++-------- sa-token-doc/doc/up/many-account.md | 64 +++++++++++++------------- sa-token-doc/doc/up/mock-person.md | 14 +++--- sa-token-doc/doc/up/mutex-login.md | 4 +- sa-token-doc/doc/up/not-cookie.md | 51 ++++++++++++-------- sa-token-doc/doc/up/password-secure.md | 2 +- sa-token-doc/doc/up/remember-me.md | 22 ++++----- sa-token-doc/doc/up/safe-auth.md | 54 ++++++++++++++++++++-- sa-token-doc/doc/up/search-session.md | 19 ++++---- sa-token-doc/doc/up/token-prefix.md | 10 ++-- sa-token-doc/doc/up/token-style.md | 12 ++--- sa-token-doc/doc/use/config.md | 12 ++++- 14 files changed, 199 insertions(+), 129 deletions(-) diff --git a/sa-token-doc/doc/up/global-filter.md b/sa-token-doc/doc/up/global-filter.md index 35da50bb..d5a56dea 100644 --- a/sa-token-doc/doc/up/global-filter.md +++ b/sa-token-doc/doc/up/global-filter.md @@ -6,14 +6,14 @@ 之前的章节中,我们学习了“根据拦截器实现路由拦截鉴权”,其实在大多数web框架中,使用过滤器可以实现同样的功能,本章我们就利用Sa-Token全局过滤器来实现路由拦截器鉴权。 首先我们先梳理清楚一个问题,既然拦截器已经可以实现路由鉴权,为什么还要用过滤器再实现一遍呢?简而言之: -1. 相比于拦截器,过滤器更加底层,执行时机更靠前,有利于防渗透扫描 -2. 过滤器可以拦截静态资源,方便我们做一些权限控制 -3. 部分Web框架根本就没有提供拦截器功能,但几乎所有的Web框架都会提供过滤器机制 +1. 相比于拦截器,过滤器更加底层,执行时机更靠前,有利于防渗透扫描。 +2. 过滤器可以拦截静态资源,方便我们做一些权限控制。 +3. 部分Web框架根本就没有提供拦截器功能,但几乎所有的Web框架都会提供过滤器机制。 但是过滤器也有一些缺点,比如: -1. 由于太过底层,导致无法率先拿到`HandlerMethod`对象,无法据此添加一些额外功能 -2. 由于拦截的太全面了,导致我们需要对很多特殊路由(如`/favicon.ico`)做一些额外处理 -3. 在Spring中,过滤器中抛出的异常无法进入全局`@ExceptionHandler`,我们必须额外编写代码进行异常处理 +1. 由于太过底层,导致无法率先拿到`HandlerMethod`对象,无法据此添加一些额外功能。 +2. 由于拦截的太全面了,导致我们需要对很多特殊路由(如`/favicon.ico`)做一些额外处理。 +3. 在Spring中,过滤器中抛出的异常无法进入全局`@ExceptionHandler`,我们必须额外编写代码进行异常处理。 Sa-Token同时提供过滤器和拦截器机制,不是为了让谁替代谁,而是为了让大家根据自己的实际业务合理选择,拥有更多的发挥空间。 @@ -75,9 +75,9 @@ public class SaTokenConfigure { ``` ##### 注意事项: -- 在`[认证函数]`里,你可以写和拦截器里一致的代码,进行路由匹配鉴权,参考:[路由拦截鉴权](/use/route-check) -- 由于过滤器中抛出的异常不进入全局异常处理,所以你必须提供`[异常处理函数]`来处理`[认证函数]`里抛出的异常 -- 在`[异常处理函数]`里的返回值,将作为字符串输出到前端,如果需要定制化返回数据,请注意其中的格式转换 +- 在`[认证函数]`里,你可以写和拦截器里一致的代码,进行路由匹配鉴权,参考:[路由拦截鉴权](/use/route-check)。 +- 由于过滤器中抛出的异常不进入全局异常处理,所以你必须提供`[异常处理函数]`来处理`[认证函数]`里抛出的异常。 +- 在`[异常处理函数]`里的返回值,将作为字符串输出到前端,如果需要定制化返回数据,请注意其中的格式转换。 改写 `setError` 函数的响应格式示例: ``` java @@ -93,7 +93,7 @@ JSON 工具类可参考:[Hutool-Json](https://hutool.cn/docs/#/json/JSONUtil) ### 在 WebFlux 中注册过滤器 `Spring WebFlux`中不提供拦截器机制,因此若你的项目需要路由鉴权功能,过滤器是你唯一的选择,在`Spring WebFlux`注册过滤器的流程与上述流程几乎完全一致, -除了您需要将过滤器名称由`SaServletFilter`更换为`SaReactorFilter`以外,其它所有步骤均可参考以上示例 +除了您需要将过滤器名称由`SaServletFilter`更换为`SaReactorFilter`以外,其它所有步骤均可参考以上示例。 ``` java /** * [Sa-Token 权限认证] 配置类 diff --git a/sa-token-doc/doc/up/global-listener.md b/sa-token-doc/doc/up/global-listener.md index 934009c7..fc17ce9f 100644 --- a/sa-token-doc/doc/up/global-listener.md +++ b/sa-token-doc/doc/up/global-listener.md @@ -1,8 +1,8 @@ # 全局侦听器 -接口`SaTokenListener`是Sa-Token的全局侦听器,通过实现此接口,你可以在用户登陆、退出、被踢下线等关键性操作时进行一些AOP操作 +接口`SaTokenListener`是Sa-Token的全局侦听器,通过实现此接口,你可以在用户登陆、退出、被踢下线等关键性操作时进行一些AOP操作。 -框架对此侦听器的默认实现是log日志输出,你可以通过配置`sa-token.is-log=true`开启 +框架对此侦听器的默认实现是log日志输出,你可以通过配置`sa-token.is-log=true`开启。 下面我们演示一下如何自定义侦听器的实现: @@ -11,7 +11,7 @@ ### 自定义侦听器实现 -新建`MySaTokenListener.java`,继承`SaTokenListener`接口,并添加上注解`@Component`,保证此类被`SpringBoot`扫描到 +新建`MySaTokenListener.java`,继承`SaTokenListener`接口,并添加上注解`@Component`,保证此类被`SpringBoot`扫描到: ``` java /** diff --git a/sa-token-doc/doc/up/integ-redis.md b/sa-token-doc/doc/up/integ-redis.md index 4c9cf408..3b04b3b8 100644 --- a/sa-token-doc/doc/up/integ-redis.md +++ b/sa-token-doc/doc/up/integ-redis.md @@ -1,46 +1,46 @@ # Sa-Token 集成 Redis --- -Sa-token默认将数据保存在内存中,此模式读写速度最快,且避免了序列化与反序列化带来的性能消耗,但是此模式也有一些缺点,比如: +Sa-token 默认将数据保存在内存中,此模式读写速度最快,且避免了序列化与反序列化带来的性能消耗,但是此模式也有一些缺点,比如: -1. 重启后数据会丢失 -2. 无法在分布式环境中共享数据 +1. 重启后数据会丢失。 +2. 无法在分布式环境中共享数据。 -为此,Sa-Token提供了扩展接口,你可以轻松将会话数据存储在 `Redis`、`Memcached`等专业的缓存中间件中, -做到重启数据不丢失,而且保证分布式环境下多节点的会话一致性 +为此,Sa-Token 提供了扩展接口,你可以轻松将会话数据存储在 `Redis`、`Memcached`等专业的缓存中间件中, +做到重启数据不丢失,而且保证分布式环境下多节点的会话一致性。 -以下是官方提供的Redis集成包: +以下是官方提供的 Redis 集成包: --- -### 方式1. Sa-Token 整合 Redis (使用jdk默认序列化方式) +### 方式1、Sa-Token 整合 Redis (使用 jdk 默认序列化方式) ``` xml - + cn.dev33 sa-token-dao-redis ${sa.top.version} ``` -优点:兼容性好,缺点:Session序列化后基本不可读,对开发者来讲等同于乱码 +优点:兼容性好,缺点:Session 序列化后基本不可读,对开发者来讲等同于乱码。 -### 方式2. Sa-Token 整合 Redis(使用jackson序列化方式) +### 方式2、Sa-Token 整合 Redis(使用 jackson 序列化方式) ``` xml - + cn.dev33 sa-token-dao-redis-jackson ${sa.top.version} ``` -优点:Session序列化后可读性强,可灵活手动修改,缺点:兼容性稍差 +优点:Session 序列化后可读性强,可灵活手动修改,缺点:兼容性稍差。 -### 集成Redis请注意: +### 集成 Redis 请注意: -**1. 无论使用哪种序列化方式,你都必须为项目提供一个Redis实例化方案,例如:** +**1. 无论使用哪种序列化方式,你都必须为项目提供一个 Redis 实例化方案,例如:** ``` xml @@ -49,8 +49,8 @@ Sa-token默认将数据保存在内存中,此模式读写速度最快,且避 ``` -**2. 引入了依赖,我还需要为Redis配置连接信息吗?**
-需要!只有项目初始化了正确的Redis实例,`Sa-Token`才可以使用Redis进行数据持久化,参考以下`yml配置`: +**2. 引入了依赖,我还需要为 Redis 配置连接信息吗?**
+需要!只有项目初始化了正确的 Redis 实例,`Sa-Token`才可以使用 Redis 进行数据持久化,参考以下`yml配置`: ``` java # 端口 spring: @@ -79,11 +79,11 @@ spring: ``` -**3. 集成Redis后,是我额外手动保存数据,还是框架自动保存?**
-框架自动保存。集成`Redis`只需要引入对应的`pom依赖`即可,框架所有上层API保持不变 +**3. 集成 Redis 后,是我额外手动保存数据,还是框架自动保存?**
+框架自动保存。集成 `Redis` 只需要引入对应的 `pom依赖` 即可,框架所有上层 API 保持不变。 **4. 集成包版本问题**
-Sa-Token-Redis 集成包的版本尽量与 Sa-Token-Starter 集成包的版本一致,否则可能出现兼容性问题 +Sa-Token-Redis 集成包的版本尽量与 Sa-Token-Starter 集成包的版本一致,否则可能出现兼容性问题。

diff --git a/sa-token-doc/doc/up/many-account.md b/sa-token-doc/doc/up/many-account.md index e32d3518..ff73198b 100644 --- a/sa-token-doc/doc/up/many-account.md +++ b/sa-token-doc/doc/up/many-account.md @@ -1,41 +1,41 @@ # 多账户认证 --- -### 0、需求场景 +### 1、需求场景 有的时候,我们会在一个项目中设计两套账号体系,比如一个电商系统的 `user表` 和 `admin表`, -在这种场景下,如果两套账号我们都使用 `StpUtil` 类的API进行登录鉴权,那么势必会发生逻辑冲突 +在这种场景下,如果两套账号我们都使用 `StpUtil` 类的API进行登录鉴权,那么势必会发生逻辑冲突。 -在Sa-Token中,这个问题的模型叫做:多账户体系认证 +在Sa-Token中,这个问题的模型叫做:多账户体系认证。 -要解决这个问题,我们必须有一个合理的机制将这两套账号的授权给区分开,让它们互不干扰才行 +要解决这个问题,我们必须有一个合理的机制将这两套账号的授权给区分开,让它们互不干扰才行。 -### 1、演进思路 +### 2、演进思路 假如说我们的 user表 和 admin表 都有一个 id=10001 的账号,它们对应的登录代码:`StpUtil.login(10001)` 是一样的, 那么问题来了:在`StpUtil.getLoginId()`获取到的账号id如何区分它是User用户,还是Admin用户? 你可能会想到为他们加一个固定前缀,比如`StpUtil.login("User_" + 10001)`、`StpUtil.login("Admin_" + 10001)`,这样确实是可以解决问题的, -但是同样的:你需要在`StpUtil.getLoginId()`时再裁剪掉相应的前缀才能获取真正的账号id,这样一增一减就让我们的代码变得无比啰嗦 +但是同样的:你需要在`StpUtil.getLoginId()`时再裁剪掉相应的前缀才能获取真正的账号id,这样一增一减就让我们的代码变得无比啰嗦。 那么,有没有从框架层面支持的,更优雅的解决方案呢? -### 2、解决方案 +### 3、解决方案 前面几篇介绍的api调用,都是经过 StpUtil 类的各种静态方法进行授权认证, 而如果我们深入它的源码,[点此阅览](https://gitee.com/dromara/sa-token/blob/master/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java)
-就会发现,此类并没有任何代码逻辑,唯一做的事就是对成员变量`stpLogic`的各个API包装一下进行转发 +就会发现,此类并没有任何代码逻辑,唯一做的事就是对成员变量`stpLogic`的各个API包装一下进行转发。 这样做有两个优点: -- StpLogic 类的所有函数都可以被重写,按需扩展 -- 在构造方法时随意传入一个不同的 `loginType`,就可以再造一套账号登录体系 +- StpLogic 类的所有函数都可以被重写,按需扩展。 +- 在构造方法时随意传入一个不同的 `loginType`,就可以再造一套账号登录体系。 -### 3、操作示例 +### 4、操作示例 比如说,对于原生`StpUtil`类,我们只做`admin账号`权限认证,而对于`user账号`,我们则: -1. 新建一个新的权限认证类,比如: `StpUserUtil.java` -2. 将`StpUtil.java`类的全部代码复制粘贴到 `StpUserUtil.java`里 +1. 新建一个新的权限认证类,比如: `StpUserUtil.java`。 +2. 将`StpUtil.java`类的全部代码复制粘贴到 `StpUserUtil.java`里。 3. 更改一下其 `LoginType`, 比如: ``` java @@ -50,16 +50,16 @@ public class StpUserUtil { } ``` -4. 接下来就可以像调用`StpUtil.java`一样调用 `StpUserUtil.java`了,这两套账号认证的逻辑是完全隔离的 +4. 接下来就可以像调用`StpUtil.java`一样调用 `StpUserUtil.java`了,这两套账号认证的逻辑是完全隔离的。 > 成品样例参考:[码云 StpUserUtil.java](https://gitee.com/dromara/sa-token/blob/dev/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java) -### 4、在多账户模式下使用注解鉴权 -框架默认的注解鉴权 如`@SaCheckLogin` 只针对原生`StpUtil`进行鉴权 +### 5、在多账户模式下使用注解鉴权 +框架默认的注解鉴权 如`@SaCheckLogin` 只针对原生`StpUtil`进行鉴权。 例如,我们在一个方法上加上`@SaCheckLogin`注解,这个注解只会放行通过`StpUtil.login(id)`进行登录的会话, -而对于通过`StpUserUtil.login(id)`进行登录的都会话,则始终不会通过校验 +而对于通过`StpUserUtil.login(id)`进行登录的都会话,则始终不会通过校验。 那么如何告诉`@SaCheckLogin`要鉴别的是哪套账号的登录会话呢?很简单,你只需要指定一下注解的type属性即可: @@ -72,17 +72,18 @@ public String info() { } ``` -注:`@SaCheckRole("xxx")`、`@SaCheckPermission("xxx")`同理,亦可根据type属性指定其校验的账号体系,此属性默认为`""`,代表使用原生`StpUtil`账号体系 +注:`@SaCheckRole("xxx")`、`@SaCheckPermission("xxx")`同理,亦可根据type属性指定其校验的账号体系,此属性默认为`""`,代表使用原生`StpUtil`账号体系。 -### 5、使用注解合并简化代码 -交流群里有同学反应,虽然可以根据 `@SaCheckLogin(type = "user")` 指定账号类型,但几十上百个注解都加上这个的话,还是有些繁琐,代码也不够优雅,有么有更改的解决方案? +### 6、使用注解合并简化代码 +交流群里有同学反应,虽然可以根据 `@SaCheckLogin(type = "user")` 指定账号类型,但几十上百个注解都加上这个的话,还是有些繁琐,代码也不够优雅,有么有更简单的解决方案? -我们期待一种`[注解继承/合并]`的能力,即:自定义一个注解,标注上`@SaCheckLogin(type = "user")`,然后在方法上标注这个自定义注解,效果等同于标注`@SaCheckLogin(type = "user")` +我们期待一种`[注解继承/合并]`的能力,即:自定义一个注解,标注上`@SaCheckLogin(type = "user")`, +然后在方法上标注这个自定义注解,效果等同于标注`@SaCheckLogin(type = "user")`。 -很遗憾,JDK默认的注解处理器并没有提供这种`[注解继承/合并]`的能力,不过好在我们可以利用 Spring 的注解处理器,达到同样的目的 +很遗憾,JDK默认的注解处理器并没有提供这种`[注解继承/合并]`的能力,不过好在我们可以利用 Spring 的注解处理器,达到同样的目的。 -1. 重写Sa-Token默认的注解处理器 +1. 重写Sa-Token默认的注解处理器: ``` java @Configuration @@ -97,7 +98,7 @@ public class SaTokenConfigure { } ``` -2. 自定义一个注解 +2. 自定义一个注解: ``` java /** @@ -112,7 +113,7 @@ public @interface SaUserCheckLogin { } ``` -3. 接下来就可以使用我们的自定义注解了 +3. 接下来就可以使用我们的自定义注解了: ``` java // 使用 @SaUserCheckLogin 的效果等同于使用:@SaCheckLogin(type = "user") @@ -123,15 +124,16 @@ public String info() { } ``` -注:其它注解 `@SaCheckRole("xxx")`、`@SaCheckPermission("xxx")`同理,完整示例参考:[码云:自定义注解](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at) +注:其它注解 `@SaCheckRole("xxx")`、`@SaCheckPermission("xxx")`同理, +完整示例参考:[码云:自定义注解](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at)。 -### 6、同端多登陆 -假设我们不仅需要在后台同时集成两套账号,我们还需要在一个客户端同时登陆两套账号(业务场景举例:一个APP中可以同时登陆商家账号和用户账号) +### 7、同端多登陆 +假设我们不仅需要在后台同时集成两套账号,我们还需要在一个客户端同时登陆两套账号(业务场景举例:一个APP中可以同时登陆商家账号和用户账号)。 -如果我们不做任何特殊处理的话,在客户端会发生`token覆盖`,新登录的token会覆盖掉旧登录的token从而导致旧登录失效 +如果我们不做任何特殊处理的话,在客户端会发生`token覆盖`,新登录的token会覆盖掉旧登录的token从而导致旧登录失效。 那么如何解决这个问题?
很简单,我们只要更改一下 `StpUserUtil` 的 `TokenName` 即可,参考示例如下: @@ -154,10 +156,10 @@ public class StpUserUtil { } ``` -再次调用 `StpUserUtil.login(10001)` 进行登录授权时,token的名称将不再是 `satoken`,而是我们重写后的 `satoken-user` +再次调用 `StpUserUtil.login(10001)` 进行登录授权时,token的名称将不再是 `satoken`,而是我们重写后的 `satoken-user`。 -### 7、不同体系不同 SaTokenConfig 配置 +### 8、不同体系不同 SaTokenConfig 配置 如果自定义的 StpUserUtil 需要使用不同 SaTokenConfig 对象, 也很简单,参考示例如下: ``` java diff --git a/sa-token-doc/doc/up/mock-person.md b/sa-token-doc/doc/up/mock-person.md index 9743d70e..e53537e4 100644 --- a/sa-token-doc/doc/up/mock-person.md +++ b/sa-token-doc/doc/up/mock-person.md @@ -2,10 +2,10 @@ --- -以上介绍的api都是操作当前账号,对当前账号进行各种鉴权操作,你可能会问,我能不能对别的账号进行一些操作?
-比如:查看账号10001有无某个权限码、获取 账号id=10002 的 `User-Session`,等等... +以上介绍的 API 都是操作当前账号,对当前账号进行各种鉴权操作,你可能会问,我能不能对别的账号进行一些操作?
+比如:查看账号 10001 有无某个权限码、获取 账号 id=10002 的 `User-Session`,等等... -Sa-Token在api设计时充分考虑了这一点,暴露出多个api进行此类操作 +Sa-Token 在 API 设计时充分考虑了这一点,暴露出多个api进行此类操作: ## 有关操作其它账号的api @@ -36,7 +36,7 @@ StpUtil.hasPermission(10001, "user:add"); 有时候,我们需要直接将当前会话的身份切换为其它账号,比如: ``` java -// 将当前会话[身份临时切换]为其它账号 +// 将当前会话[身份临时切换]为其它账号(本次请求内有效) StpUtil.switchTo(10044); // 此时再调用此方法会返回 10044 (我们临时切换到的账号id) @@ -46,12 +46,12 @@ StpUtil.getLoginId(); StpUtil.endSwitch(); ``` -你还可以: 直接在一个代码段里方法内,临时切换身份为指定loginId(此方式无需手动调用`StpUtil.endSwitch()`关闭身份切换) +你还可以:直接在一个代码段里方法内,临时切换身份为指定loginId(此方式无需手动调用`StpUtil.endSwitch()`关闭身份切换) ``` java System.out.println("------- [身份临时切换]调用开始..."); StpUtil.switchTo(10044, () -> { - System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch()); - System.out.println("获取当前登录账号id: " + StpUtil.getLoginId()); + System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch()); // 输出 true + System.out.println("获取当前登录账号id: " + StpUtil.getLoginId()); // 输出 10044 }); System.out.println("------- [身份临时切换]调用结束..."); ``` diff --git a/sa-token-doc/doc/up/mutex-login.md b/sa-token-doc/doc/up/mutex-login.md index 1bd55ee1..66721f8c 100644 --- a/sa-token-doc/doc/up/mutex-login.md +++ b/sa-token-doc/doc/up/mutex-login.md @@ -1,7 +1,7 @@ # 同端互斥登录 -如果你经常使用腾讯QQ,就会发现它的登录有如下特点:它可以手机电脑同时在线,但是不能在两个手机上同时登录一个账号
-同端互斥登录,指的就是像腾讯QQ一样,在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线 +如果你经常使用腾讯QQ,就会发现它的登录有如下特点:它可以手机电脑同时在线,但是不能在两个手机上同时登录一个账号。
+同端互斥登录,指的就是:像腾讯QQ一样,在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线。 diff --git a/sa-token-doc/doc/up/not-cookie.md b/sa-token-doc/doc/up/not-cookie.md index 6f2e4018..d6c636aa 100644 --- a/sa-token-doc/doc/up/not-cookie.md +++ b/sa-token-doc/doc/up/not-cookie.md @@ -1,33 +1,48 @@ # 前后台分离(无Cookie模式) --- -### 何为无Cookie模式? +### 何为无 Cookie 模式? -无Cookie:特指不支持Cookie功能的终端,通俗来讲就是我们常说的 —— **前后台分离模式** +无 Cookie 模式:特指不支持 Cookie 功能的终端,通俗来讲就是我们常说的 —— **前后台分离模式**。 -常规 Web 端鉴权方法,一般由 `Cookie模式` 完成,而 Cookie 有两个特性: -1. 可由后端控制写入 -2. 每次请求自动提交 +常规 Web 端鉴权方法,一般由 `Cookie模式` 完成,而 Cookie 有两个特性: +1. 可由后端控制写入。 +2. 每次请求自动提交。 这就使得我们在前端代码中,无需任何特殊操作,就能完成鉴权的全部流程(因为整个流程都是后端控制完成的)
而在app、小程序等前后台分离场景中,一般是没有 Cookie 这一功能的,此时大多数人都会一脸懵逼,咋进行鉴权啊? 见招拆招,其实答案很简单: -- 不能后端控制写入了,就前端自己写入(难点在**后端如何将 Token 传递到前端**) -- 每次请求不能自动提交了,那就手动提交(难点在**前端如何将 Token 传递到后端**,同时**后端将其读取出来**) +- 不能后端控制写入了,就前端自己写入。(难点在**后端如何将 Token 传递到前端**) +- 每次请求不能自动提交了,那就手动提交。(难点在**前端如何将 Token 传递到后端**,同时**后端将其读取出来**) ### 1、后端将 token 返回到前端 -1. 首先调用 `StpUtil.login(id)` 进行登录 -2. 调用 `StpUtil.getTokenInfo()` 返回当前会话的token详细参数 - - 此方法返回一个对象,其有两个关键属性:`tokenName`和`tokenValue`(token 的名称和 token 的值) - - 将此对象传递到前台,让前端人员将这两个值保存到本地 +1. 首先调用 `StpUtil.login(id)` 进行登录。 +2. 调用 `StpUtil.getTokenInfo()` 返回当前会话的 token 详细参数。 + - 此方法返回一个对象,其有两个关键属性:`tokenName`和`tokenValue`(token 的名称和 token 的值)。 + - 将此对象传递到前台,让前端人员将这两个值保存到本地。 + +代码示例: +``` java +// 登录接口 +@RequestMapping("doLogin") +public SaResult doLogin() { + // 第1步,先登录上 + StpUtil.login(10001); + // 第2步,获取 Token 相关参数 + SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); + // 第3步,返回给前端 + return SaResult.data(tokenInfo); +} +``` + ### 2、前端将 token 提交到后端 -1. 无论是app还是小程序,其传递方式都大同小异 -2. 那就是,将 token 塞到请求`header`里 ,格式为:`{tokenName: tokenValue}` +1. 无论是app还是小程序,其传递方式都大同小异。 +2. 那就是,将 token 塞到请求`header`里 ,格式为:`{tokenName: tokenValue}`。 3. 以经典跨端框架 [uni-app](https://uniapp.dcloud.io/) 为例: **方式1,简单粗暴** @@ -76,14 +91,14 @@ uni.request({ }); ``` -4. 只要按照如此方法将`token`值传递到后端,Sa-Token 就能像传统PC端一样自动读取到 token 值,进行鉴权 -5. 你可能会有疑问,难道我每个`ajax`都要写这么一坨?岂不是麻烦死了 - - 你当然不能每个 ajax 都写这么一坨,因为这种重复性代码都是要封装在一个函数里统一调用的 +4. 只要按照如此方法将`token`值传递到后端,Sa-Token 就能像传统PC端一样自动读取到 token 值,进行鉴权。 +5. 你可能会有疑问,难道我每个`ajax`都要写这么一坨?岂不是麻烦死了? + - 你当然不能每个 ajax 都写这么一坨,因为这种重复性代码都是要封装在一个函数里统一调用的。 ### 其它解决方案? 如果你对 Cookie 非常了解,那你就会明白,所谓 Cookie ,本质上就是一个特殊的`header`参数而已, -而既然它只是一个 header 参数,我们就能手动模拟实现它,从而完成鉴权操作 +而既然它只是一个 header 参数,我们就能手动模拟实现它,从而完成鉴权操作。 -这其实是对`无Cookie模式`的另一种解决方案,有兴趣的同学可以百度了解一下,在此暂不赘述 +这其实是对`无Cookie模式`的另一种解决方案,有兴趣的同学可以百度了解一下,在此暂不赘述。 diff --git a/sa-token-doc/doc/up/password-secure.md b/sa-token-doc/doc/up/password-secure.md index be563e0a..1395c9cc 100644 --- a/sa-token-doc/doc/up/password-secure.md +++ b/sa-token-doc/doc/up/password-secure.md @@ -1,7 +1,7 @@ # 密码加密 严格来讲,密码加密不属于 [权限认证] 的范畴,但是对于大多数系统来讲,密码加密又是安全认证不可或缺的部分, -所以,应大家要求,`Sa-Token`在`v1.14版本`添加密码加密模块,该模块非常简单,仅仅封装了一些常见的加密算法 +所以,应大家要求,`Sa-Token`在 v1.14 版本添加密码加密模块,该模块非常简单,仅仅封装了一些常见的加密算法。 diff --git a/sa-token-doc/doc/up/remember-me.md b/sa-token-doc/doc/up/remember-me.md index 97dc60ef..e9f55d97 100644 --- a/sa-token-doc/doc/up/remember-me.md +++ b/sa-token-doc/doc/up/remember-me.md @@ -1,16 +1,16 @@ # [记住我] 模式 --- -如图所示,一般网站的登录界面都会有一个 **`[记住我]`** 按钮,当你勾选它后,即使你关闭浏览器再次打开网站,也依然会处于登录状态,无须重复验证密码 +如图所示,一般网站的登录界面都会有一个 **`[记住我]`** 按钮,当你勾选它后,即使你关闭浏览器再次打开网站,也依然会处于登录状态,无须重复验证密码: ![../static/login-view.png](https://oss.dev33.cn/sa-token/doc/login-view.png) 那么在Sa-Token中,如何做到 [ 记住我 ] 功能呢? -### 在sa-token中实现记住我功能 +### 在 Sa-Token 中实现记住我功能 -Sa-Token的登录授权,**默认就是`[记住我]`模式**,为了实现`[非记住我]`模式, 你需要在登录时如下设置: +Sa-Token的登录授权,**默认就是`[记住我]`模式**,为了实现`[非记住我]`模式,你需要在登录时如下设置: ``` java // 设置登录账号id为10001,第二个参数指定是否为[记住我],当此值为false后,关闭浏览器后再次打开需要重新登录 @@ -22,12 +22,12 @@ StpUtil.login(10001, false); ### 实现原理 Cookie作为浏览器提供的默认会话跟踪机制,其生命周期有两种形式,分别是: -- 临时Cookie:有效期为本次会话,只要关闭浏览器窗口,Cookie就会消失 -- 持久Cookie:有效期为一个具体的时间,在时间未到期之前,即使用户关闭了浏览器Cookie也不会消失 +- 临时Cookie:有效期为本次会话,只要关闭浏览器窗口,Cookie就会消失。 +- 持久Cookie:有效期为一个具体的时间,在时间未到期之前,即使用户关闭了浏览器Cookie也不会消失。 利用Cookie的此特性,我们便可以轻松实现 [记住我] 模式: -- 勾选 [记住我] 按钮时:调用`StpUtil.login(10001, true)`,在浏览器写入一个`持久Cookie`储存 Token,此时用户即使重启浏览器 Token 依然有效 -- 不勾选 [记住我] 按钮时:调用`StpUtil.login(10001, false)`,在浏览器写入一个`临时Cookie`储存 Token,此时用户在重启浏览器后 Token 便会消失,导致会话失效 +- 勾选 [记住我] 按钮时:调用`StpUtil.login(10001, true)`,在浏览器写入一个`持久Cookie`储存 Token,此时用户即使重启浏览器 Token 依然有效。 +- 不勾选 [记住我] 按钮时:调用`StpUtil.login(10001, false)`,在浏览器写入一个`临时Cookie`储存 Token,此时用户在重启浏览器后 Token 便会消失,导致会话失效。 @@ -38,7 +38,7 @@ Cookie作为浏览器提供的默认会话跟踪机制,其生命周期有两 此时机智的你😏很快发现一个问题,Cookie虽好,却无法在前后端分离环境下使用,那是不是代表上述方案在APP、小程序等环境中无效? 准确的讲,答案是肯定的,任何基于Cookie的认证方案在前后台分离环境下都会失效(原因在于这些客户端默认没有实现Cookie功能),不过好在,这些客户端一般都提供了替代方案, -唯一遗憾的是,此场景中token的生命周期需要我们在前端手动控制 +唯一遗憾的是,此场景中token的生命周期需要我们在前端手动控制: 以经典跨端框架 [uni-app](https://uniapp.dcloud.io/) 为例,我们可以使用如下方式达到同样的效果: ``` js @@ -62,8 +62,8 @@ Remember me, it's too easy! -### 登录时指定token有效期 -登录时不仅可以指定是否为`[记住我]`模式,还可以指定一个特定的时间作为token有效时长,如下示例: +### 登录时指定 Token 有效期 +登录时不仅可以指定是否为`[记住我]`模式,还可以指定一个特定的时间作为 Token 有效时长,如下示例: ``` java // 示例1: // 指定token有效期(单位: 秒),如下所示token七天有效 @@ -74,7 +74,7 @@ StpUtil.login(10001, new SaLoginModel().setTimeout(60 * 60 * 24 * 7)); StpUtil.login(10001, new SaLoginModel() .setDevice("PC") // 此次登录的客户端设备类型, 用于[同端互斥登录]时指定此次登录的设备类型 .setIsLastingCookie(true) // 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在) - .setTimeout(60 * 60 * 24 * 7) // 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值) + .setTimeout(60 * 60 * 24 * 7) // 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的 timeout 值) .setToken("xxxx-xxxx-xxxx-xxxx") // 预定此次登录的生成的Token ); ``` diff --git a/sa-token-doc/doc/up/safe-auth.md b/sa-token-doc/doc/up/safe-auth.md index be3e12ca..a4088003 100644 --- a/sa-token-doc/doc/up/safe-auth.md +++ b/sa-token-doc/doc/up/safe-auth.md @@ -1,18 +1,18 @@ # 二级认证 -在某些敏感操作下,我们需要对已登录的会话进行二次验证 +在某些敏感操作下,我们需要对已登录的会话进行二次验证。 比如代码托管平台的仓库删除操作,尽管我们已经登录了账号,当我们点击 **[删除]** 按钮时,还是需要再次输入一遍密码,这么做主要为了两点: -1. 保证操作者是当前账号本人 -2. 增加操作步骤,防止误删除重要数据 +1. 保证操作者是当前账号本人。 +2. 增加操作步骤,防止误删除重要数据。 这就是我们本篇要讲的 —— 二级认证,即:在已登录会话的基础上,进行再次验证,提高会话的安全性。 --- -## 具体API +### 具体API 在`Sa-Token`中进行二级认证非常简单,只需要使用以下API: @@ -34,7 +34,7 @@ StpUtil.closeSafe(); ``` -## 使用注解进行二级认证 +### 使用注解进行二级认证 在一个方法上使用 `@SaCheckSafe` 注解,可以在代码进入之前此方法之前进行一次二级认证 ``` java // 二级认证:必须二级认证之后才能进入该方法 @@ -48,3 +48,47 @@ public String add() { 详细使用方法可参考:[注解鉴权](/use/at-check),此处不再赘述 + +### 一个小示例 + +一个完整的二级认证业务流程,应该大致如下: +``` java +// 删除仓库 +@RequestMapping("deleteProject") +public SaResult deleteProject(String projectId) { + // 第1步,先检查当前会话是否已完成二级认证 + if(StpUtil.isSafe()) { + return SaResult.error("请完成二级认证后再次访问接口"); + } + + // 第2步,如果已完成二级认证,则开始执行业务逻辑 + // ... + + // 第3步,返回结果 + return SaResult.ok(); +} + +// 提供密码进行二级认证 +@RequestMapping("openSafe") +public SaResult openSafe(String password) { + // 比对密码(此处只是举例,真实项目时可拿其它参数进行校验) + if("123456".equals(password)) { + + // 比对成功,为当前会话打开二级认证,有效期为120秒 + StpUtil.openSafe(120); + return SaResult.ok("二级认证成功"); + } + + // 如果密码校验失败,则二级认证也会失败 + return SaResult.error("二级认证失败"); +} +``` + +调用步骤: +1. 前端调用 `deleteProject` 接口,尝试删除仓库。 +2. 后端校验会话尚未完成二级认证,返回: `请完成二级认证后再次访问接口`。 +3. 前端将信息提示给用户,用户输入密码,调用 `openSafe` 接口。 +4. 后端比对用户输入的密码,完成二级认证,有效期为:120秒。 +5. 前端在 120 秒内再次调用 `deleteProject` 接口,尝试删除仓库。 +6. 后端校验会话已完成二级认证,仓库删除成功。 + diff --git a/sa-token-doc/doc/up/search-session.md b/sa-token-doc/doc/up/search-session.md index b431b800..aaa661eb 100644 --- a/sa-token-doc/doc/up/search-session.md +++ b/sa-token-doc/doc/up/search-session.md @@ -1,7 +1,8 @@ # 会话治理 -尽管框架将大部分操作提供了简易的封装,但在一些特殊场景下,我们仍需要绕过框架,直达数据底层进行一些操作
-Sa-Token提供以下API助你直接操作会话列表 +尽管框架将大部分操作提供了简易的封装,但在一些特殊场景下,我们仍需要绕过框架,直达数据底层进行一些操作。 + +Sa-Token提供以下API助你直接操作会话列表: --- @@ -21,9 +22,9 @@ StpUtil.searchTokenSessionId(String keyword, int start, int size); #### 参数详解: -- `keyword`: 查询关键字,只有包括这个字符串的token值才会被查询出来 -- `start`: 数据开始处索引, 值为-1时代表一次性取出所有数据 -- `size`: 要获取的数据条数 +- `keyword`: 查询关键字,只有包括这个字符串的 token 值才会被查询出来。 +- `start`: 数据开始处索引, 值为-1时代表一次性取出所有数据。 +- `size`: 要获取的数据条数。 使用示例: ``` java @@ -39,10 +40,10 @@ for (String token : tokenList) { #### 注意事项: 由于会话查询底层采用了遍历方式获取数据,当数据量过大时此操作将会比较耗时,有多耗时呢?这里提供一份参考数据: -- 单机模式下:百万会话取出10条token平均耗时 `0.255s` -- Redis模式下:百万会话取出10条token平均耗时 `3.322s` +- 单机模式下:百万会话取出10条 Token 平均耗时 `0.255s`。 +- Redis模式下:百万会话取出10条 Token 平均耗时 `3.322s`。 -请根据业务实际水平合理调用API +请根据业务实际水平合理调用API。 -> 如果需要实时获取当前登录人数或者需要在用户退出后自动触发某事件等, 建议采用websocket技术 \ No newline at end of file +> 如果需要实时获取当前登录人数或者需要在用户退出后自动触发某事件等, 建议采用websocket技术。 \ No newline at end of file diff --git a/sa-token-doc/doc/up/token-prefix.md b/sa-token-doc/doc/up/token-prefix.md index 92ad69e8..7d88a46c 100644 --- a/sa-token-doc/doc/up/token-prefix.md +++ b/sa-token-doc/doc/up/token-prefix.md @@ -10,7 +10,7 @@ } ``` -此时后端如果不做任何特殊处理,框架将会把`Bearer `视为token的一部分,无法正常读取token信息,导致鉴权失败 +此时后端如果不做任何特殊处理,框架将会把`Bearer `视为token的一部分,无法正常读取token信息,导致鉴权失败。 为此,我们需要在yml中添加如下配置: ``` java @@ -19,12 +19,12 @@ sa-token: token-prefix: Bearer ``` -此时 Sa-Token 便可在读取 Token 时裁剪掉 `Bearer`,成功获取`xxxx-xxxx-xxxx-xxxx` +此时 Sa-Token 便可在读取 Token 时裁剪掉 `Bearer`,成功获取`xxxx-xxxx-xxxx-xxxx`。 ### 注意点 -1. Token前缀 与 Token值 之间必须有一个空格 -2. 一旦配置了 Token前缀,则前端提交token时,必须带有前缀,否则会导致框架无法读取token -3. 由于`Cookie`中无法存储空格字符,也就意味配置token前缀后,Cookie鉴权方式将会失效,此时只能将token提交到`header`里进行传输 +1. Token前缀 与 Token值 之间必须有一个空格。 +2. 一旦配置了 Token前缀,则前端提交 `Token` 时,必须带有前缀,否则会导致框架无法读取 Token。 +3. 由于`Cookie`中无法存储空格字符,也就意味配置 Token 前缀后,Cookie 鉴权方式将会失效,此时只能将 Token 提交到`header`里进行传输。 diff --git a/sa-token-doc/doc/up/token-style.md b/sa-token-doc/doc/up/token-style.md index dbd8fdb7..8cbc31da 100644 --- a/sa-token-doc/doc/up/token-style.md +++ b/sa-token-doc/doc/up/token-style.md @@ -1,14 +1,14 @@ # 自定义 Token 风格 -本篇介绍token生成的各种风格,以及自定义token生成策略 +本篇介绍token生成的各种风格,以及自定义token生成策略。 --- ## 内置风格 -Sa-Token默认的token生成策略是uuid风格,其模样类似于:`623368f0-ae5e-4475-a53f-93e4225f16ae`
-如果你对这种风格不太感冒,还可以将token生成设置为其他风格 +Sa-Token默认的token生成策略是uuid风格,其模样类似于:`623368f0-ae5e-4475-a53f-93e4225f16ae`。
+如果你对这种风格不太感冒,还可以将token生成设置为其他风格。 怎么设置呢?只需要在yml配置文件里设置 `sa-token.token-style=风格类型` 即可,其有多种取值: @@ -33,11 +33,11 @@ Sa-Token默认的token生成策略是uuid风格,其模样类似于:`623368f0 ``` -## 自定义token生成策略 +## 自定义 Token 生成策略 -如果你觉着以上风格都不是你喜欢的类型,那么你还可以**自定义token生成策略**,来定制化token生成风格
+如果你觉着以上风格都不是你喜欢的类型,那么你还可以**自定义token生成策略**,来定制化token生成风格。
-怎么做呢?只需要重写 `SaStrategy` 策略类的 `createToken` 算法即可 +怎么做呢?只需要重写 `SaStrategy` 策略类的 `createToken` 算法即可: #### 参考步骤如下: diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index f04eb9bb..89410b71 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -121,7 +121,7 @@ Server 端: | ticketTimeout | long | 300 | ticket 有效期 (单位: 秒) | | allowUrl | String | * | 所有允许的授权回调地址,多个用逗号隔开(不在此列表中的URL将禁止下放ticket),参考:[SSO整合:配置域名校验](/sso/sso-check-domain) | | isSlo | Boolean | false | 是否打开单点注销功能 | -| isHttp | Boolean | false | 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo) | +| isHttp | Boolean | false | 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo),参考:[详解](/use/config?id=isHttp) | | secretkey | String | null | 调用秘钥 (用于SSO模式三单点注销的接口通信身份校验) | @@ -131,7 +131,7 @@ Client 端: | :-------- | :-------- | :-------- | :-------- | | authUrl | String | null | 配置 Server 端单点登录授权地址 | | isSlo | Boolean | false | 是否打开单点注销功能 | -| isHttp | Boolean | false | 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo) | +| isHttp | Boolean | false | 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo),参考:[详解](/use/config?id=isHttp) | | checkTicketUrl| String | null | 配置 Server 端的 ticket 校验地址 | | userinfoUrl | String | null | 配置 Server 端查询 userinfo 地址 | | sloUrl | String | null | 配置 Server 端单点注销地址 | @@ -244,3 +244,11 @@ sa-token: - 此值为 false 时:四种模式(`isCode、isImplicit、isPassword、isClient`)是否生效,依靠局部配置+全局配置(两个都为 true 时才打开) +#### isHttp + +配置含义:是否打开单点登录模式三。 + +- 此配置项为 false 时,代表使用SSO模式二:使用 Redis 校验 ticket 值、删除 Redis 数据做到单点注销、使用 Redis 同步 Userinfo 数据。 +- 此配置项为 true 时,代表使用SSO模式三:使用 Http 请求校验 ticket 值、使用 Http 请求做到单点注销、使用 Http 请求同步 Userinfo 数据。 + + From 6207637e8672813ec9c5481cd4dffad61740c2e9 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 5 Jul 2022 18:52:34 +0800 Subject: [PATCH 036/144] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=96=87=E6=A1=A3?= =?UTF-8?q?=EF=BC=9A=E5=9C=A8=E5=A4=9A=E8=B4=A6=E6=88=B7=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=B8=AD=E9=9B=86=E6=88=90=20jwt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/plugin/jwt-extend.md | 55 ++++++++++++++++++--------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/sa-token-doc/doc/plugin/jwt-extend.md b/sa-token-doc/doc/plugin/jwt-extend.md index 3c11c169..e1cfad82 100644 --- a/sa-token-doc/doc/plugin/jwt-extend.md +++ b/sa-token-doc/doc/plugin/jwt-extend.md @@ -111,26 +111,8 @@ public class LoginController { eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbklkIjoiMTAwMDEiLCJybiI6IjZYYzgySzBHVWV3Uk5NTTl1dFdjbnpFZFZHTVNYd3JOIn0.F_7fbHsFsDZmckHlGDaBuwDotZwAjZ0HB14DRujQfOQ ``` -### 5、扩展参数 -你可以通过以下方式在登录时注入扩展参数: -``` java -// 登录10001账号,并为生成的 Token 追加扩展参数name -StpUtil.login(10001, SaLoginConfig.setExtra("name", "zhangsan")); - -// 连缀写法追加多个 -StpUtil.login(10001, SaLoginConfig - .setExtra("name", "zhangsan") - .setExtra("age", 18) - .setExtra("role", "超级管理员")); - -// 获取扩展参数 -String name = StpUtil.getExtra("name"); -``` - - - -### 6、不同模式策略对比 +### 5、不同模式策略对比 注入不同模式会让框架具有不同的行为策略,以下是三种模式的差异点(为方便叙述,以下比较以同时引入 jwt 与 Redis 作为前提): @@ -157,5 +139,40 @@ String name = StpUtil.getExtra("name"); +### 6、扩展参数 +你可以通过以下方式在登录时注入扩展参数: + +``` java +// 登录10001账号,并为生成的 Token 追加扩展参数name +StpUtil.login(10001, SaLoginConfig.setExtra("name", "zhangsan")); + +// 连缀写法追加多个 +StpUtil.login(10001, SaLoginConfig + .setExtra("name", "zhangsan") + .setExtra("age", 18) + .setExtra("role", "超级管理员")); + +// 获取扩展参数 +String name = StpUtil.getExtra("name"); +``` + + + +### 7、在多账户模式中集成 jwt +sa-token-jwt 插件默认只为 `StpUtil` 注入 `StpLogicJwtFoxXxx` 实现,自定义的 `StpUserUtil` 是不会自动注入的,我们需要帮其手动注入: + +``` java +/** + * 为 StpUserUtil 注入 StpLogicJwt 实现 + */ +@Autowired +public void setUserStpLogic() { + StpUserUtil.stpLogic = new StpLogicJwtForSimple(StpUserUtil.TYPE); + SaManager.putStpLogic(StpUserUtil.stpLogic); +} +``` + + + From 4491daef46e1db77bfdddab5d7e68a10e7105782 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 5 Jul 2022 19:02:36 +0800 Subject: [PATCH 037/144] =?UTF-8?q?=E8=A1=A5=E5=85=85=E8=B5=9E=E8=B5=8F?= =?UTF-8?q?=E6=A1=88=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/sa-token-donate.md | 1 + sa-token-doc/index.html | 3 +++ 2 files changed, 4 insertions(+) diff --git a/sa-token-doc/doc/more/sa-token-donate.md b/sa-token-doc/doc/more/sa-token-donate.md index 2ff469c8..c85f1ec2 100644 --- a/sa-token-doc/doc/more/sa-token-donate.md +++ b/sa-token-doc/doc/more/sa-token-donate.md @@ -19,6 +19,7 @@ Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永 | 赞助人 | 赞助金额 | 留言 | 时间 | | :-------- | :-------- | :-------- | :-------- | +| [zhihong](https://gitee.com/zzh13520704819) | ¥ 20.0 | 感谢您的开源项目! | 2022-06-20 | | [风如歌](https://gitee.com/the-wind-is-like-a-song) | ¥ 10.0 | 这个框架简直满足了我所有对于安全框架的需求,赞一个,加油sa-token加油中国开源! | 2022-06-17 | | [qiuyue](https://gitee.com/bmlt) | ¥ 10.0 | satoken牛逼 | 2022-06-16 | | [刘时立](https://gitee.com/liu-shili) | ¥ 10.0 | 非常棒的开源项目! | 2022-06-13 | diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 31ea14a1..10b81ea7 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -309,6 +309,9 @@ + + +

From a7de15bd7ce22f64dfd0b0d66899e65b3b7abac8 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 6 Jul 2022 10:17:59 +0800 Subject: [PATCH 038/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20Quarkus=20?= =?UTF-8?q?=E9=9B=86=E6=88=90=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/start/download.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sa-token-doc/doc/start/download.md b/sa-token-doc/doc/start/download.md index 35d3a10e..ff8e94f1 100644 --- a/sa-token-doc/doc/start/download.md +++ b/sa-token-doc/doc/start/download.md @@ -62,6 +62,17 @@ ``` + +参考:[quarkus-sa-token](https://github.com/quarkiverse/quarkus-sa-token) +``` xml + + + io.quarkiverse.satoken + quarkus-satoken-resteasy + 1.0.1 + +``` + 注:如果你的项目没有使用Spring,但是Web框架是基于 ServletAPI 规范的,可以引入此包 ``` xml @@ -116,6 +127,11 @@ implementation 'cn.dev33:sa-token-jfinal-plugin:${sa.top.version}' implementation 'cn.dev33:sa-token-jboot-plugin:${sa.top.version}' ``` + +``` xml +implementation 'io.quarkiverse.satoken:quarkus-satoken-resteasy:1.0.1' +``` + ``` xml implementation 'cn.dev33:sa-token-servlet:${sa.top.version}' From 2d6e42578673cde9060488886ec3735c27f15dc4 Mon Sep 17 00:00:00 2001 From: noear Date: Thu, 7 Jul 2022 18:22:19 +0800 Subject: [PATCH 039/144] =?UTF-8?q?sa-token-solon-plugin=EF=BC=9A=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=20solon=20=E4=B8=BA=201.9.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-demo/sa-token-demo-solon/pom.xml | 4 ++-- sa-token-plugin/sa-token-dao-redisx/pom.xml | 2 +- sa-token-starter/sa-token-solon-plugin/pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sa-token-demo/sa-token-demo-solon/pom.xml b/sa-token-demo/sa-token-demo-solon/pom.xml index 2a73e17c..21857a8d 100644 --- a/sa-token-demo/sa-token-demo-solon/pom.xml +++ b/sa-token-demo/sa-token-demo-solon/pom.xml @@ -14,11 +14,11 @@ - + org.noear solon-web - 1.8.0 + 1.9.1 diff --git a/sa-token-plugin/sa-token-dao-redisx/pom.xml b/sa-token-plugin/sa-token-dao-redisx/pom.xml index 62bdb4fb..2a07ab56 100644 --- a/sa-token-plugin/sa-token-dao-redisx/pom.xml +++ b/sa-token-plugin/sa-token-dao-redisx/pom.xml @@ -33,7 +33,7 @@ org.noear solon-test - 1.7.5 + 1.9.1 test diff --git a/sa-token-starter/sa-token-solon-plugin/pom.xml b/sa-token-starter/sa-token-solon-plugin/pom.xml index 0b8b1144..cc9e876a 100644 --- a/sa-token-starter/sa-token-solon-plugin/pom.xml +++ b/sa-token-starter/sa-token-solon-plugin/pom.xml @@ -20,7 +20,7 @@ org.noear solon - 1.8.0 + 1.9.1 From 819622eb659fa9e2fbb72a012fce560b867aa567 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 9 Jul 2022 19:43:16 +0800 Subject: [PATCH 040/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/start/download.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sa-token-doc/doc/start/download.md b/sa-token-doc/doc/start/download.md index ff8e94f1..0cdb8f83 100644 --- a/sa-token-doc/doc/start/download.md +++ b/sa-token-doc/doc/start/download.md @@ -69,7 +69,7 @@ io.quarkiverse.satoken quarkus-satoken-resteasy - 1.0.1 + 1.30.0 ``` @@ -129,7 +129,7 @@ implementation 'cn.dev33:sa-token-jboot-plugin:${sa.top.version}' ``` xml -implementation 'io.quarkiverse.satoken:quarkus-satoken-resteasy:1.0.1' +implementation 'io.quarkiverse.satoken:quarkus-satoken-resteasy:1.30.0' ``` From 46e3317c1fa7bc2375a6ee39162a7d7aac709b01 Mon Sep 17 00:00:00 2001 From: noear Date: Tue, 12 Jul 2022 13:55:30 +0800 Subject: [PATCH 041/144] =?UTF-8?q?sa-token-solon-plugin=EF=BC=9A=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=20solon=20=E4=B8=BA=201.9.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-demo/sa-token-demo-solon/pom.xml | 2 +- .../sa-token-solon-plugin/pom.xml | 2 +- .../cn/dev33/satoken/solon/XPluginImp.java | 14 +- ...java => SaTokenAnnotationInterceptor.java} | 4 +- .../solon/integration/SaTokenPathFilter.java | 62 ++++-- .../integration/SaTokenPathInterceptor.java | 183 ++++++++++++++++++ .../SaContextForSolon.java | 2 +- .../src/test/java/demo/App.java | 12 ++ .../src/test/java/demo/Config.java | 41 ++++ .../src/test/java/demo2/App.java | 12 ++ .../src/test/java/demo2/Config.java | 53 +++++ .../src/test/resources/app.yml | 26 +++ 12 files changed, 383 insertions(+), 30 deletions(-) rename sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/{SaTokenMethodInterceptor.java => SaTokenAnnotationInterceptor.java} (74%) create mode 100644 sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathInterceptor.java rename sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/{integration => model}/SaContextForSolon.java (96%) create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/java/demo/App.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/java/demo/Config.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/App.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/Config.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/resources/app.yml diff --git a/sa-token-demo/sa-token-demo-solon/pom.xml b/sa-token-demo/sa-token-demo-solon/pom.xml index 21857a8d..0f803e9f 100644 --- a/sa-token-demo/sa-token-demo-solon/pom.xml +++ b/sa-token-demo/sa-token-demo-solon/pom.xml @@ -18,7 +18,7 @@ org.noear solon-web - 1.9.1 + 1.9.2 diff --git a/sa-token-starter/sa-token-solon-plugin/pom.xml b/sa-token-starter/sa-token-solon-plugin/pom.xml index cc9e876a..0f44b91d 100644 --- a/sa-token-starter/sa-token-solon-plugin/pom.xml +++ b/sa-token-starter/sa-token-solon-plugin/pom.xml @@ -20,7 +20,7 @@ org.noear solon - 1.9.1 + 1.9.2 diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java index 65823601..1e7a9786 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java @@ -16,8 +16,8 @@ import cn.dev33.satoken.id.SaIdUtil; import cn.dev33.satoken.json.SaJsonTemplate; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.sign.SaSignTemplate; -import cn.dev33.satoken.solon.integration.SaContextForSolon; -import cn.dev33.satoken.solon.integration.SaTokenMethodInterceptor; +import cn.dev33.satoken.solon.model.SaContextForSolon; +import cn.dev33.satoken.solon.integration.SaTokenAnnotationInterceptor; import cn.dev33.satoken.stp.StpInterface; import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; @@ -31,11 +31,11 @@ public class XPluginImp implements Plugin { @Override public void start(AopContext context) { - context.beanAroundAdd(SaCheckPermission.class, SaTokenMethodInterceptor.INSTANCE); - context.beanAroundAdd(SaCheckRole.class, SaTokenMethodInterceptor.INSTANCE); - context.beanAroundAdd(SaCheckLogin.class, SaTokenMethodInterceptor.INSTANCE); - context.beanAroundAdd(SaCheckSafe.class, SaTokenMethodInterceptor.INSTANCE); - context.beanAroundAdd(SaCheckBasic.class, SaTokenMethodInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckPermission.class, SaTokenAnnotationInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckRole.class, SaTokenAnnotationInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckLogin.class, SaTokenAnnotationInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckSafe.class, SaTokenAnnotationInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckBasic.class, SaTokenAnnotationInterceptor.INSTANCE); //集成初始化 diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenMethodInterceptor.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenAnnotationInterceptor.java similarity index 74% rename from sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenMethodInterceptor.java rename to sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenAnnotationInterceptor.java index 950b05e2..2f73754c 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenMethodInterceptor.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenAnnotationInterceptor.java @@ -9,9 +9,9 @@ import cn.dev33.satoken.strategy.SaStrategy; * @author noear * @since 1.4 */ -public class SaTokenMethodInterceptor implements Interceptor { +public class SaTokenAnnotationInterceptor implements Interceptor { - public static final SaTokenMethodInterceptor INSTANCE = new SaTokenMethodInterceptor(); + public static final SaTokenAnnotationInterceptor INSTANCE = new SaTokenAnnotationInterceptor(); @Override public Object doIntercept(Invocation inv) throws Throwable { diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathFilter.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathFilter.java index 6014aca8..ef5e760e 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathFilter.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathFilter.java @@ -1,12 +1,12 @@ package cn.dev33.satoken.solon.integration; - import cn.dev33.satoken.exception.BackResultException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.exception.StopMatchException; import cn.dev33.satoken.filter.SaFilterAuthStrategy; import cn.dev33.satoken.filter.SaFilterErrorStrategy; import cn.dev33.satoken.router.SaRouter; +import org.noear.solon.Utils; import org.noear.solon.core.handle.Context; import org.noear.solon.core.handle.Filter; import org.noear.solon.core.handle.FilterChain; @@ -16,24 +16,26 @@ import java.util.Arrays; import java.util.List; /** - * @author noear 2021/5/30 created + * @author noear + * @since 1.9 */ public class SaTokenPathFilter implements Filter { - + // ------------------------ 设置此过滤器 拦截 & 放行 的路由 /** * 拦截路由 */ - private List includeList = new ArrayList<>(); + protected List includeList = new ArrayList<>(); /** * 放行路由 */ - private List excludeList = new ArrayList<>(); + protected List excludeList = new ArrayList<>(); /** * 添加 [拦截路由] + * * @param paths 路由 * @return 对象自身 */ @@ -44,6 +46,7 @@ public class SaTokenPathFilter implements Filter { /** * 添加 [放行路由] + * * @param paths 路由 * @return 对象自身 */ @@ -54,6 +57,7 @@ public class SaTokenPathFilter implements Filter { /** * 写入 [拦截路由] 集合 + * * @param pathList 路由集合 * @return 对象自身 */ @@ -64,6 +68,7 @@ public class SaTokenPathFilter implements Filter { /** * 写入 [放行路由] 集合 + * * @param pathList 路由集合 * @return 对象自身 */ @@ -74,6 +79,7 @@ public class SaTokenPathFilter implements Filter { /** * 获取 [拦截路由] 集合 + * * @return see note */ public List getIncludeList() { @@ -82,6 +88,7 @@ public class SaTokenPathFilter implements Filter { /** * 获取 [放行路由] 集合 + * * @return see note */ public List getExcludeList() { @@ -94,22 +101,29 @@ public class SaTokenPathFilter implements Filter { /** * 认证函数:每次请求执行 */ - public SaFilterAuthStrategy auth = r -> {}; + protected SaFilterAuthStrategy auth = r -> { + }; /** * 异常处理函数:每次[认证函数]发生异常时执行此函数 */ - public SaFilterErrorStrategy error = e -> { - throw new SaTokenException(e); + protected SaFilterErrorStrategy error = e -> { + if (e instanceof SaTokenException) { + throw (SaTokenException) e; + } else { + throw new SaTokenException(e); + } }; /** * 前置函数:在每次[认证函数]之前执行 */ - public SaFilterAuthStrategy beforeAuth = r -> {}; + protected SaFilterAuthStrategy beforeAuth = r -> { + }; /** * 写入[认证函数]: 每次请求执行 + * * @param auth see note * @return 对象自身 */ @@ -120,6 +134,7 @@ public class SaTokenPathFilter implements Filter { /** * 写入[异常处理函数]:每次[认证函数]发生异常时执行此函数 + * * @param error see note * @return 对象自身 */ @@ -130,6 +145,7 @@ public class SaTokenPathFilter implements Filter { /** * 写入[前置函数]:在每次[认证函数]之前执行 + * * @param beforeAuth see note * @return 对象自身 */ @@ -144,23 +160,33 @@ public class SaTokenPathFilter implements Filter { try { // 执行全局过滤器 SaRouter.match(includeList).notMatch(excludeList).check(r -> { - beforeAuth.run(null); + beforeAuth.run(null); auth.run(null); }); - + } catch (StopMatchException e) { - - } catch (Throwable e) { - // 1. 获取异常处理策略结果 - String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e)); + + } catch (SaTokenException e) { + // 1. 获取异常处理策略结果 + Object result; + if (e instanceof BackResultException) { + result = e.getMessage(); + } else { + result = error.run(e); + } // 2. 写入输出流 - ctx.contentType("text/plain; charset=utf-8"); - ctx.output(result); + if(result != null) { + ctx.render(result); + } + ctx.setHandled(true); return; + } catch (Throwable e) { + // 异常解包 + throw Utils.throwableUnwrap(e); //solon 的最后层还有保底处理 } // 执行 chain.doFilter(ctx); } -} +} \ No newline at end of file diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathInterceptor.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathInterceptor.java new file mode 100644 index 00000000..b89adca0 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathInterceptor.java @@ -0,0 +1,183 @@ +package cn.dev33.satoken.solon.integration; + +import cn.dev33.satoken.exception.BackResultException; +import cn.dev33.satoken.exception.SaTokenException; +import cn.dev33.satoken.exception.StopMatchException; +import cn.dev33.satoken.filter.SaFilterAuthStrategy; +import cn.dev33.satoken.filter.SaFilterErrorStrategy; +import cn.dev33.satoken.router.SaRouter; +import org.noear.solon.core.handle.Context; +import org.noear.solon.core.handle.Handler; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * sa-token基于路由的拦截式鉴权 + * @author kong + */ +public class SaTokenPathInterceptor implements Handler { + + // ------------------------ 设置此过滤器 拦截 & 放行 的路由 + + /** + * 拦截路由 + */ + protected List includeList = new ArrayList<>(); + + /** + * 放行路由 + */ + protected List excludeList = new ArrayList<>(); + + /** + * 添加 [拦截路由] + * + * @param paths 路由 + * @return 对象自身 + */ + public SaTokenPathInterceptor addInclude(String... paths) { + includeList.addAll(Arrays.asList(paths)); + return this; + } + + /** + * 添加 [放行路由] + * + * @param paths 路由 + * @return 对象自身 + */ + public SaTokenPathInterceptor addExclude(String... paths) { + excludeList.addAll(Arrays.asList(paths)); + return this; + } + + /** + * 写入 [拦截路由] 集合 + * + * @param pathList 路由集合 + * @return 对象自身 + */ + public SaTokenPathInterceptor setIncludeList(List pathList) { + includeList = pathList; + return this; + } + + /** + * 写入 [放行路由] 集合 + * + * @param pathList 路由集合 + * @return 对象自身 + */ + public SaTokenPathInterceptor setExcludeList(List pathList) { + excludeList = pathList; + return this; + } + + /** + * 获取 [拦截路由] 集合 + * + * @return see note + */ + public List getIncludeList() { + return includeList; + } + + /** + * 获取 [放行路由] 集合 + * + * @return see note + */ + public List getExcludeList() { + return excludeList; + } + + + // ------------------------ 钩子函数 + + /** + * 认证函数:每次请求执行 + */ + protected SaFilterAuthStrategy auth = r -> { + }; + + /** + * 异常处理函数:每次[认证函数]发生异常时执行此函数 + */ + protected SaFilterErrorStrategy error = e -> { + if (e instanceof SaTokenException) { + throw (SaTokenException) e; + } else { + throw new SaTokenException(e); + } + }; + + /** + * 前置函数:在每次[认证函数]之前执行 + */ + protected SaFilterAuthStrategy beforeAuth = r -> { + }; + + /** + * 写入[认证函数]: 每次请求执行 + * + * @param auth see note + * @return 对象自身 + */ + public SaTokenPathInterceptor setAuth(SaFilterAuthStrategy auth) { + this.auth = auth; + return this; + } + + /** + * 写入[异常处理函数]:每次[认证函数]发生异常时执行此函数 + * + * @param error see note + * @return 对象自身 + */ + public SaTokenPathInterceptor setError(SaFilterErrorStrategy error) { + this.error = error; + return this; + } + + /** + * 写入[前置函数]:在每次[认证函数]之前执行 + * + * @param beforeAuth see note + * @return 对象自身 + */ + public SaTokenPathInterceptor setBeforeAuth(SaFilterAuthStrategy beforeAuth) { + this.beforeAuth = beforeAuth; + return this; + } + + + @Override + public void handle(Context ctx) throws Throwable { + try { + // 执行全局过滤器 + SaRouter.match(includeList).notMatch(excludeList).check(r -> { + beforeAuth.run(null); + auth.run(null); + }); + + } catch (StopMatchException e) { + + } catch (SaTokenException e) { + // 1. 获取异常处理策略结果 + Object result; + if (e instanceof BackResultException) { + result = e.getMessage(); + } else { + result = error.run(e); + } + + // 2. 写入输出流 + if(result != null) { + ctx.render(result); + } + ctx.setHandled(true); + } + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaContextForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java similarity index 96% rename from sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaContextForSolon.java rename to sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java index e372aa01..e6ef1cc6 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaContextForSolon.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java @@ -1,4 +1,4 @@ -package cn.dev33.satoken.solon.integration; +package cn.dev33.satoken.solon.model; import cn.dev33.satoken.context.SaTokenContext; import cn.dev33.satoken.context.model.SaRequest; diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/App.java b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/App.java new file mode 100644 index 00000000..ac68f579 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/App.java @@ -0,0 +1,12 @@ +package demo; + +import org.noear.solon.Solon; + +/** + * @author noear 2022/3/30 created + */ +public class App { + public static void main(String[] args) { + Solon.start(App.class, args); + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/Config.java b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/Config.java new file mode 100644 index 00000000..8bd221b1 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/Config.java @@ -0,0 +1,41 @@ +package demo; + +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.solon.integration.SaTokenPathFilter; +import cn.dev33.satoken.stp.StpUtil; +import org.noear.solon.annotation.Bean; +import org.noear.solon.annotation.Configuration; +import org.noear.solon.core.handle.Filter; + +/** + * @author noear 2022/3/30 created + */ +@Configuration +public class Config { + + @Bean + public Filter saTokenFilter() { + return new SaTokenPathFilter() + // 指定 [拦截路由] 与 [放行路由] + .addInclude("/**").addExclude("/favicon.ico") + + // 认证函数: 每次请求执行 + .setAuth(s -> { + SaRouter.match("/**", StpUtil::checkLogin); + + // 根据路由划分模块,不同模块不同鉴权 + SaRouter.match("/user/**", r -> StpUtil.checkPermission("user")); + SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin")); + SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods")); + SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders")); + }) + + // 异常处理函数:每次认证函数发生异常时执行此函数 + .setError(e -> { + System.out.println("---------- sa全局异常 "); + System.out.println(e.getMessage()); + StpUtil.login(123); + return e.getMessage(); + }); + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/App.java b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/App.java new file mode 100644 index 00000000..8b9ff8b5 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/App.java @@ -0,0 +1,12 @@ +package demo2; + +import org.noear.solon.Solon; + +/** + * @author noear 2022/3/30 created + */ +public class App { + public static void main(String[] args) { + Solon.start(App.class, args); + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/Config.java b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/Config.java new file mode 100644 index 00000000..7b970b72 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/Config.java @@ -0,0 +1,53 @@ +package demo2; + +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.solon.integration.SaTokenPathInterceptor; +import cn.dev33.satoken.stp.StpUtil; +import org.noear.solon.Solon; +import org.noear.solon.annotation.Bean; +import org.noear.solon.annotation.Configuration; + +/** + * @author noear 2022/7/11 created + */ +@Configuration +public class Config { + @Bean + public void saTokenPathInterceptor() { + Solon.app().before(new SaTokenPathInterceptor() + // 指定 [拦截路由] 与 [放行路由] + .addInclude("/**").addExclude("/favicon.ico") + + // 认证函数: 每次请求执行 + .setAuth(s -> { + SaRouter.match("/**", StpUtil::checkLogin); + + // 根据路由划分模块,不同模块不同鉴权 + SaRouter.match("/user/**", r -> StpUtil.checkPermission("user")); + SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin")); + SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods")); + SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders")); + }) + + // 异常处理函数:每次认证函数发生异常时执行此函数 + .setError(e -> { + System.out.println("---------- sa全局异常 "); + System.out.println(e.getMessage()); + StpUtil.login(123); + return e.getMessage(); + }) + ); + } + + @Bean + public void saTokenPathInterceptor2() { + Solon.app().before((ctx) -> { + SaRouter.match("/**", StpUtil::checkLogin); + // 根据路由划分模块,不同模块不同鉴权 + SaRouter.match("/user/**", r -> StpUtil.checkPermission("user")); + SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin")); + SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods")); + SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders")); + }); + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/resources/app.yml b/sa-token-starter/sa-token-solon-plugin/src/test/resources/app.yml new file mode 100644 index 00000000..5dd15890 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/resources/app.yml @@ -0,0 +1,26 @@ + + +# sa-token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: satoken + # token有效期,单位s 默认30天, -1代表永不过期 + timeout: 2592000 + # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 + activity-timeout: -1 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + allow-concurrent-login: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: true + # token风格 + token-style: uuid + # 是否输出操作日志 + is-log: false + + +sa-token-dao: #名字可以随意取 + redis: + server: "localhost:6379" + password: 123456 + db: 1 + maxTotal: 200 From ac9d1fa9f84941c0aaade4d950ab44af60e4b1c2 Mon Sep 17 00:00:00 2001 From: AppleOfGray Date: Thu, 14 Jul 2022 02:38:04 +0000 Subject: [PATCH 042/144] =?UTF-8?q?update=20sa-token-doc/doc/up/many-accou?= =?UTF-8?q?nt.md.=20=E8=BF=98=E6=98=AF=E9=92=88=E5=AF=B9=E8=B7=B3=E7=BA=A7?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E7=9A=84=E6=96=B0=E4=BA=BA=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/up/many-account.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/up/many-account.md b/sa-token-doc/doc/up/many-account.md index ff73198b..f0bb2905 100644 --- a/sa-token-doc/doc/up/many-account.md +++ b/sa-token-doc/doc/up/many-account.md @@ -74,7 +74,7 @@ public String info() { 注:`@SaCheckRole("xxx")`、`@SaCheckPermission("xxx")`同理,亦可根据type属性指定其校验的账号体系,此属性默认为`""`,代表使用原生`StpUtil`账号体系。 - +> 使用注解必须[添加注解拦截器](https://sa-token.dev33.cn/doc/index.html#/use/at-check?id=_1%e3%80%81%e6%b3%a8%e5%86%8c%e6%8b%a6%e6%88%aa%e5%99%a8) ### 6、使用注解合并简化代码 交流群里有同学反应,虽然可以根据 `@SaCheckLogin(type = "user")` 指定账号类型,但几十上百个注解都加上这个的话,还是有些繁琐,代码也不够优雅,有么有更简单的解决方案? From 4870ef068f41ff449d429ce013a471f722f045bf Mon Sep 17 00:00:00 2001 From: Joe <956459902@163.com> Date: Mon, 18 Jul 2022 07:12:03 +0000 Subject: [PATCH 043/144] update sa-token-doc/doc/more/link.md. --- sa-token-doc/doc/more/link.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index d5bf2940..f269b1be 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -74,6 +74,8 @@ - [[ fhs-framework ]](https://gitee.com/fhs-opensource/fhs-framework):基于Springboot+Springcloud + Mybatis Plus + sa-token+ vue + elementui 的快速开发平台(低代码开发平台),本框架永远免费,永久全开源 +- [[ chaos ]](https://gitee.com/qishanor/chaos):一个基于 SpringBoot + Sa-Token + Mybatis-Plus的快速开发框架,前端vue-element-avue,内置代码生成器,代码最简洁,最佳学习实践方案。 + From 54d435b457303f9d41d9eef9f7a67a31658e46d2 Mon Sep 17 00:00:00 2001 From: sikadai Date: Mon, 18 Jul 2022 18:39:25 +0800 Subject: [PATCH 044/144] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=94=AF=E6=8C=81red?= =?UTF-8?q?is=E7=9A=84String=E4=BD=9C=E4=B8=BAsession=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E5=8C=96=E7=9A=84=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/dev33/satoken/session/SaSession.java | 11 +- .../cn/dev33/satoken/session/TokenSign.java | 105 ++++---- sa-token-plugin/pom.xml | 1 + .../sa-token-dao-redis-string/.gitignore | 13 + .../sa-token-dao-redis-string/pom.xml | 34 +++ .../satoken/dao/SaTokenDaoRedisString.java | 236 ++++++++++++++++++ .../main/resources/META-INF/spring.factories | 1 + 7 files changed, 353 insertions(+), 48 deletions(-) create mode 100644 sa-token-plugin/sa-token-dao-redis-string/.gitignore create mode 100644 sa-token-plugin/sa-token-dao-redis-string/pom.xml create mode 100644 sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java create mode 100644 sa-token-plugin/sa-token-dao-redis-string/src/main/resources/META-INF/spring.factories diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index 0812ec49..865482e1 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -108,7 +108,14 @@ public class SaSession implements Serializable { /** * 此Session绑定的token签名列表 */ - private final List tokenSignList = new Vector<>(); + private Vector tokenSignList = new Vector<>(); + + /** + * 设置此Session绑定的token签名列表-反序列化需要 + */ + public void setTokenSignList(Vector tokenSignList) { + this.tokenSignList = tokenSignList; + } /** * 此Session绑定的token签名列表 @@ -597,6 +604,4 @@ public class SaSession implements Serializable { return dataMap.keySet(); } - - } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/TokenSign.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/TokenSign.java index 4af451a3..4d65a980 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/TokenSign.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/TokenSign.java @@ -3,62 +3,77 @@ package cn.dev33.satoken.session; import java.io.Serializable; /** - * Token 签名 Model - * + * Token 签名 Model + *

* 挂在到SaSession上的token签名 - * - * @author kong * + * @author kong */ public class TokenSign implements Serializable { - /** - * - */ - private static final long serialVersionUID = 1406115065849845073L; + /** + * + */ + private static final long serialVersionUID = 1406115065849845073L; - /** - * token值 - */ - private String value; + /** + * token值 + */ + private String value; - /** - * 所属设备类型 - */ - private String device; + /** + * 所属设备类型 + */ + private String device; - /** 构建一个 */ - public TokenSign() { - } + /** + * 构建一个 + */ + public TokenSign() { + } - /** - * 构建一个 - * - * @param value token值 - * @param device 所属设备类型 - */ - public TokenSign(String value, String device) { - this.value = value; - this.device = device; - } + /** + * 构建一个 + * + * @param value token值 + * @param device 所属设备类型 + */ + public TokenSign(String value, String device) { + this.value = value; + this.device = device; + } - /** - * @return token值 - */ - public String getValue() { - return value; - } + /** + * @return token值 + */ + public String getValue() { + return value; + } - /** - * @return 所属设备类型 - */ - public String getDevice() { - return device; - } + /** + * @return 所属设备类型 + */ + public String getDevice() { + return device; + } - @Override - public String toString() { - return "TokenSign [value=" + value + ", device=" + device + "]"; - } + /** + * 反序列化需要 + */ + public void setValue(String value) { + this.value = value; + } + + /** + * 反序列化需要 + */ + public void setDevice(String device) { + this.device = device; + } + + @Override + public String toString() { + return "TokenSign [value=" + value + ", device=" + device + "]"; + } } diff --git a/sa-token-plugin/pom.xml b/sa-token-plugin/pom.xml index 7b6d8dbf..61ad0051 100644 --- a/sa-token-plugin/pom.xml +++ b/sa-token-plugin/pom.xml @@ -22,6 +22,7 @@ sa-token-dao-redis sa-token-dao-redis-jackson sa-token-dao-redisx + sa-token-dao-redis-string sa-token-dialect-thymeleaf sa-token-sso sa-token-oauth2 diff --git a/sa-token-plugin/sa-token-dao-redis-string/.gitignore b/sa-token-plugin/sa-token-dao-redis-string/.gitignore new file mode 100644 index 00000000..8122f47c --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redis-string/.gitignore @@ -0,0 +1,13 @@ +target/ + +node_modules/ +bin/ +.settings/ +unpackage/ +.classpath +.project + +.factorypath + +.idea/ +.iml \ No newline at end of file diff --git a/sa-token-plugin/sa-token-dao-redis-string/pom.xml b/sa-token-plugin/sa-token-dao-redis-string/pom.xml new file mode 100644 index 00000000..f65399a3 --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redis-string/pom.xml @@ -0,0 +1,34 @@ + + + + sa-token-plugin + cn.dev33 + ${revision} + ../pom.xml + + 4.0.0 + + sa-token-dao-redix-string + + + + + cn.dev33 + sa-token-core + ${revision} + + + + org.springframework.boot + spring-boot-starter-data-redis + 2.3.3.RELEASE + + + com.alibaba + fastjson + 1.2.78 + + + \ No newline at end of file diff --git a/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java b/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java new file mode 100644 index 00000000..3b5f3717 --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java @@ -0,0 +1,236 @@ +package cn.dev33.satoken.dao; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.util.SaFoxUtil; +import com.alibaba.fastjson.JSON; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * Sa-Token持久层接口 [Redis版 (使用JDK默认序列化方式)] + * + * @author kong + * + */ +@Component +public class SaTokenDaoRedisString implements SaTokenDao { + + /** + * String专用 + */ + public StringRedisTemplate stringRedisTemplate; + + /** + * Objecy专用 + */ + public StringRedisTemplate objectRedisTemplate; + + /** + * 标记:是否已初始化成功 + */ + public boolean isInit; + + @Autowired + public void init(RedisConnectionFactory connectionFactory) { + // 指定相应的序列化方案 + StringRedisSerializer keySerializer = new StringRedisSerializer(); + StringRedisSerializer valueSerializer = new StringRedisSerializer(); + // 构建StringRedisTemplate + StringRedisTemplate stringTemplate = new StringRedisTemplate(); + stringTemplate.setConnectionFactory(connectionFactory); + stringTemplate.afterPropertiesSet(); + // 构建RedisTemplate + StringRedisTemplate template = new StringRedisTemplate(); + template.setConnectionFactory(connectionFactory); + template.setKeySerializer(keySerializer); + template.setHashKeySerializer(keySerializer); + template.setValueSerializer(valueSerializer); + template.setHashValueSerializer(valueSerializer); + template.afterPropertiesSet(); + + // 开始初始化相关组件 + if(!this.isInit) { + this.stringRedisTemplate = stringTemplate; + this.objectRedisTemplate = template; + this.isInit = true; + } + } + + + /** + * 获取Value,如无返空 + */ + @Override + public String get(String key) { + return stringRedisTemplate.opsForValue().get(key); + } + + /** + * 写入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) { + stringRedisTemplate.opsForValue().set(key, value); + } else { + stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS); + } + } + + /** + * 修改指定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) { + stringRedisTemplate.delete(key); + } + + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + return stringRedisTemplate.getExpire(key); + } + + /** + * 修改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; + } + stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS); + } + + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return objectRedisTemplate.opsForValue().get(key); + } + + @Override + public SaSession getSession(String sessionId) { + Object obj = getObject(sessionId); + if (obj == null) { + return null; + } + return JSON.parseObject(obj.toString(), SaSession.class); + } + + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + String toValue = JSON.toJSONString(object); + // 判断是否为永不过期 + if(timeout == SaTokenDao.NEVER_EXPIRE) { + objectRedisTemplate.opsForValue().set(key, toValue); + } else { + objectRedisTemplate.opsForValue().set(key, toValue, timeout, TimeUnit.SECONDS); + } + } + + /** + * 更新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) { + objectRedisTemplate.delete(key); + } + + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + return objectRedisTemplate.getExpire(key); + } + + /** + * 修改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; + } + objectRedisTemplate.expire(key, timeout, TimeUnit.SECONDS); + } + + + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size) { + Set keys = stringRedisTemplate.keys(prefix + "*" + keyword + "*"); + List list = new ArrayList(keys); + return SaFoxUtil.searchList(list, start, size); + } + + +} diff --git a/sa-token-plugin/sa-token-dao-redis-string/src/main/resources/META-INF/spring.factories b/sa-token-plugin/sa-token-dao-redis-string/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..09ff20cb --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redis-string/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.dao.SaTokenDaoRedisString \ No newline at end of file From 38811791ade76962a63cace742c66e16e84c3fdd Mon Sep 17 00:00:00 2001 From: sikadai Date: Mon, 18 Jul 2022 18:41:57 +0800 Subject: [PATCH 045/144] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java b/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java index 3b5f3717..21f5018e 100644 --- a/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java +++ b/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java @@ -17,7 +17,7 @@ import java.util.concurrent.TimeUnit; /** * Sa-Token持久层接口 [Redis版 (使用JDK默认序列化方式)] * - * @author kong + * @author sikadai * */ @Component From a31e23a9b6bcc41ab7ea4301a8d80a065ba2ca83 Mon Sep 17 00:00:00 2001 From: sikadai Date: Mon, 18 Jul 2022 18:48:29 +0800 Subject: [PATCH 046/144] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java b/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java index 21f5018e..2f849e93 100644 --- a/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java +++ b/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java @@ -15,7 +15,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; /** - * Sa-Token持久层接口 [Redis版 (使用JDK默认序列化方式)] + * Sa-Token持久层接口 [Redis版 (使用JSON字符串进行序列化)] * * @author sikadai * From 2457bc4bf9ed35a54d860347f0800092a1accbc4 Mon Sep 17 00:00:00 2001 From: yangyang Date: Wed, 27 Jul 2022 02:59:52 +0000 Subject: [PATCH 047/144] =?UTF-8?q?update=20sa-token-doc/doc/up/safe-auth.?= =?UTF-8?q?md.=20=E5=AE=8C=E5=85=A8=E7=9B=B8=E5=8F=8D=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/up/safe-auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/up/safe-auth.md b/sa-token-doc/doc/up/safe-auth.md index a4088003..02f84388 100644 --- a/sa-token-doc/doc/up/safe-auth.md +++ b/sa-token-doc/doc/up/safe-auth.md @@ -57,7 +57,7 @@ public String add() { @RequestMapping("deleteProject") public SaResult deleteProject(String projectId) { // 第1步,先检查当前会话是否已完成二级认证 - if(StpUtil.isSafe()) { + if(!StpUtil.isSafe()) { return SaResult.error("请完成二级认证后再次访问接口"); } From 5b55d5e3a23ac88295f55c1ed4c4406c86dd0d17 Mon Sep 17 00:00:00 2001 From: AppleOfGray Date: Thu, 28 Jul 2022 05:09:37 +0000 Subject: [PATCH 048/144] =?UTF-8?q?update=20sa-token-doc/doc/more/common-q?= =?UTF-8?q?uestions.md.=20springboot=E7=89=88=E6=9C=AC=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E8=A6=81=E5=88=A0=E9=99=A4=E4=B9=8B=E5=89=8D?= =?UTF-8?q?=E7=9A=84redis=E6=95=B0=E6=8D=AE(2.6.10->2.7.1=E5=8F=AF?= =?UTF-8?q?=E5=A4=8D=E7=8E=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/common-questions.md | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/sa-token-doc/doc/more/common-questions.md b/sa-token-doc/doc/more/common-questions.md index 6df141e4..1baefb33 100644 --- a/sa-token-doc/doc/more/common-questions.md +++ b/sa-token-doc/doc/more/common-questions.md @@ -90,6 +90,33 @@ jwt 的招牌便是无须借助服务端完成会话管理,如果集成`jwt` 参考:[https://blog.csdn.net/shengzhang_/article/details/119928794](https://blog.csdn.net/shengzhang_/article/details/119928794) +### 集成redis后对象模型序列化异常 +假设执行如下代码: +``` java +@Data +public class User implements Serializable { + private Long userId; + private String username; + private String password; +} + +User user = new User(); +user.setUserId(10000L); +user.setUsername("oneName"); +user.setPassword("onePass"); +StpUtil.getSession().set("userObjKey", user); // 这里报错 +``` +报错信息如下: +``` +SerializationException: Could not read JSON: +Cannot deserialize value of type `java.lang.Long` from Array value (token `JsonToken.START_ARRAY`) +``` + +springboot 集成 satoken redis 后, 一旦 springboot 切换版本就有可能出现此问题 + +原因是redis里面有之前的 satoken 会话数据, 清空 Redis 即可 + + From 061f7f811fee46c61aeba98dcf3d47964a9dc924 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 29 Jul 2022 06:16:49 +0800 Subject: [PATCH 049/144] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=B5=9E=E5=8A=A9?= =?UTF-8?q?=E8=80=85=E5=90=8D=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/sa-token-donate.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sa-token-doc/doc/more/sa-token-donate.md b/sa-token-doc/doc/more/sa-token-donate.md index c85f1ec2..2eb2e689 100644 --- a/sa-token-doc/doc/more/sa-token-donate.md +++ b/sa-token-doc/doc/more/sa-token-donate.md @@ -19,6 +19,8 @@ Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永 | 赞助人 | 赞助金额 | 留言 | 时间 | | :-------- | :-------- | :-------- | :-------- | +| [小北宸呀](https://gitee.com/a_aas) | ¥ 10.0 | 感谢您的开源项目!我就喜欢你这种把我当白痴的官方文档 | 2022-07-08 | +| [jwc_gitee](https://gitee.com/jwc-gitee) | ¥ 10.0 | 感谢您的开源项目! | 2022-07-07 | | [zhihong](https://gitee.com/zzh13520704819) | ¥ 20.0 | 感谢您的开源项目! | 2022-06-20 | | [风如歌](https://gitee.com/the-wind-is-like-a-song) | ¥ 10.0 | 这个框架简直满足了我所有对于安全框架的需求,赞一个,加油sa-token加油中国开源! | 2022-06-17 | | [qiuyue](https://gitee.com/bmlt) | ¥ 10.0 | satoken牛逼 | 2022-06-16 | From 565b122447c27b5b077bdeb1284c743b402b000c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Jul 2022 22:17:22 +0000 Subject: [PATCH 050/144] Bump fastjson in /sa-token-plugin/sa-token-dao-redis-string Bumps [fastjson](https://github.com/alibaba/fastjson) from 1.2.78 to 1.2.83. - [Release notes](https://github.com/alibaba/fastjson/releases) - [Commits](https://github.com/alibaba/fastjson/compare/1.2.78...1.2.83) --- updated-dependencies: - dependency-name: com.alibaba:fastjson dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- sa-token-plugin/sa-token-dao-redis-string/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-plugin/sa-token-dao-redis-string/pom.xml b/sa-token-plugin/sa-token-dao-redis-string/pom.xml index f65399a3..fbf0d58d 100644 --- a/sa-token-plugin/sa-token-dao-redis-string/pom.xml +++ b/sa-token-plugin/sa-token-dao-redis-string/pom.xml @@ -28,7 +28,7 @@ com.alibaba fastjson - 1.2.78 + 1.2.83 \ No newline at end of file From 62101009cf70dfc5f84ceee4a1749665239762f7 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 29 Jul 2022 08:14:13 +0800 Subject: [PATCH 051/144] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=8B=E6=83=85?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/index.css | 4 +- sa-token-doc/index.html | 98 +++++++++++++++++++++++++++++++++++------ 2 files changed, 86 insertions(+), 16 deletions(-) diff --git a/sa-token-doc/index.css b/sa-token-doc/index.css index b39167e2..7ca23902 100644 --- a/sa-token-doc/index.css +++ b/sa-token-doc/index.css @@ -112,7 +112,7 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica .s-case-link img{transition: all 0.3s;} .s-case-title,.s-case-intro{padding: 0 16px;} .s-case-title{margin-top: 20px; font-size: 18px; font-weight: 400; color: #333; font-family: "microsoft yahei";} -.s-case-intro{margin-top: 10px; font-size: 14px; line-height: 20px; color: #777; word-break:break-all;} +.s-case-intro{margin-top: 15px; font-size: 14px; line-height: 20px; color: #777; word-break:break-all;} .s-author{color: #ff5722; border: 1px #ff5722 solid; position: absolute; right: 20px; display: inline-block;} .s-author{padding: 0 5px; font-size: 12px; transform: translate(0, -25px);} @@ -149,7 +149,7 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica /* -------- 友情链接 --------- */ .com-box-you a{flex: 0 0 14.5%; line-height: 60px; height: 60px; margin: 10px;} -.com-box-you a img{min-width: 60%; max-width: 100%; vertical-align: middle; max-height: 100%;} +.com-box-you a img{min-width: 60%; max-width: 85%; vertical-align: middle; max-height: 100%;} /* -------- 底部 - 连接 --------- */ #footer{background-color: #181818;} diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 10b81ea7..1a2f31fc 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -200,13 +200,22 @@

重写 RuoYi-Cloud 所有功能 整合 SpringCloudAlibaba、Dubbo3.0、Sa-Token

-
+ + +
+ + + +

fhs-framework

+ fhs-opensource +

FHS-Framwork 是一个集成了国内外诸多优秀开源项目的快速开发平台

@@ -324,12 +333,14 @@ - +

-

友情链接

+

+ Dromara 成员项目 +

+
+

+ 为往圣继绝学,一个人或许能走的更快,但一群人会走的更远。 +

+
+
+
+ + +
+
+
+
+

友情链接

+
@@ -382,6 +451,7 @@
+
@@ -588,7 +591,7 @@ return; } // 如果不是oss上的图片 - if(img.src.indexOf('https://oss.dev33.cn') == -1) { + if(img.src.indexOf('https://oss.dev33.cn') == -1 || img.src.endsWith('.svg')) { return; } img.src = img.src + "?x-oss-process=image/resize,m_lfit,w_" + (img.width) + ",limit_0/auto-orient,0"; From 1ca4da886e751455ca9636eafbc148fa39021f59 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 29 Jul 2022 15:35:50 +0800 Subject: [PATCH 053/144] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=8B=E6=83=85?= =?UTF-8?q?=E9=93=BE=E6=8E=A5=EF=BC=9Adante-cloud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/index.html | 3 +++ .../cn/dev33/satoken/solon/model/SaContextForSolon.java | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index adf194ce..ecc88fad 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -408,6 +408,9 @@ + + + diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java index e6ef1cc6..3a9f4dee 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java @@ -1,15 +1,12 @@ package cn.dev33.satoken.solon.model; +import org.noear.solon.core.handle.Context; +import org.noear.solon.core.util.PathAnalyzer; + import cn.dev33.satoken.context.SaTokenContext; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.context.model.SaResponse; import cn.dev33.satoken.context.model.SaStorage; -import cn.dev33.satoken.solon.model.SaRequestForSolon; -import cn.dev33.satoken.solon.model.SaResponseForSolon; -import cn.dev33.satoken.solon.model.SaStorageForSolon; - -import org.noear.solon.core.handle.Context; -import org.noear.solon.core.util.PathAnalyzer; /** * @author noear From 2f5b7337ab24f1e4887e17d1d2b560fda7a4c1aa Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 29 Jul 2022 18:42:35 +0800 Subject: [PATCH 054/144] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20`SaOAuth2Handle`?= =?UTF-8?q?=20=E7=B1=BB=E4=B8=AD=20`doLogin`=20=E6=96=B9=E6=B3=95=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E4=BD=BF=E7=94=A8=20`Param.pwd`=20=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java index 763e39fc..ca323660 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java @@ -226,7 +226,7 @@ public class SaOAuth2Handle { * @return 处理结果 */ public static Object doLogin(SaRequest req, SaResponse res, SaOAuth2Config cfg) { - return cfg.getDoLoginHandle().apply(req.getParamNotNull(Param.name), req.getParamNotNull("pwd")); + return cfg.getDoLoginHandle().apply(req.getParamNotNull(Param.name), req.getParamNotNull(Param.pwd)); } /** From 5927588ec4a9e8970b65b3116da819717500faae Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 29 Jul 2022 19:05:04 +0800 Subject: [PATCH 055/144] =?UTF-8?q?=E6=95=B4=E7=90=86=E5=8F=8B=E6=83=85?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index ecc88fad..f5c430d3 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -393,7 +393,7 @@ - + From 47e6806c217c2d2f778e0004cc898b5f9a38bc4a Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 30 Jul 2022 07:06:21 +0800 Subject: [PATCH 056/144] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/dev33/satoken/session/SaSession.java | 93 +++++++++----- .../cn/dev33/satoken/session/TokenSign.java | 121 ++++++++++-------- 2 files changed, 123 insertions(+), 91 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index 865482e1..5f25f1d0 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -21,6 +21,9 @@ import cn.dev33.satoken.util.SaFoxUtil; */ public class SaSession implements Serializable { + /** + * + */ private static final long serialVersionUID = 1L; /** @@ -33,30 +36,30 @@ public class SaSession implements Serializable { */ public static final String PERMISSION_LIST = "PERMISSION_LIST"; - /** 此Session的id */ + /** 此 Session 的 id */ private String id; - /** 此Session的创建时间 */ + /** 此 Session 的创建时间(时间戳) */ private long createTime; - /** 此Session的所有挂载数据 */ + /** 此 Session 的所有挂载数据 */ private final Map dataMap = new ConcurrentHashMap<>(); // ----------------------- 构建相关 /** - * 构建一个Session对象 + * 构建一个 Session 对象 */ public SaSession() { /* - * 当Session从Redis中反序列化取出时,框架会误以为创建了新的Session, + * 当 Session 从 Redis 中反序列化取出时,框架会误以为创建了新的Session, * 因此此处不可以调用this(null); 避免监听器收到错误的通知 */ // this(null); } /** - * 构建一个Session对象 + * 构建一个 Session 对象 * @param id Session的id */ public SaSession(String id) { @@ -67,15 +70,15 @@ public class SaSession implements Serializable { } /** - * 获取此Session的id - * @return 此会话的id + * 获取此 Session 的 id + * @return 此 Session 的id */ public String getId() { return id; } /** - * 写入此Session的id + * 写入此 Session 的 id * @param id SessionId * @return 对象自身 */ @@ -85,7 +88,7 @@ public class SaSession implements Serializable { } /** - * 返回当前会话创建时间 + * 返回当前会话创建时间(时间戳) * @return 时间戳 */ public long getCreateTime() { @@ -93,7 +96,7 @@ public class SaSession implements Serializable { } /** - * 写入此Session的创建时间 + * 写入此 Session 的创建时间(时间戳) * @param createTime 时间戳 * @return 对象自身 */ @@ -103,31 +106,32 @@ public class SaSession implements Serializable { } - // ----------------------- TokenSign相关 + // ----------------------- TokenSign 相关 /** - * 此Session绑定的token签名列表 + * 此 Session 绑定的 Token 签名列表 */ private Vector tokenSignList = new Vector<>(); /** - * 设置此Session绑定的token签名列表-反序列化需要 + * 写入此 Session 绑定的 Token 签名列表 + * @param tokenSignList Token 签名列表 */ public void setTokenSignList(Vector tokenSignList) { this.tokenSignList = tokenSignList; } /** - * 此Session绑定的token签名列表 + * 获取此 Session 绑定的 Token 签名列表 * - * @return token签名列表 + * @return Token 签名列表 */ public List getTokenSignList() { return tokenSignList; } /** - * 返回token签名列表的拷贝副本 + * 获取 Token 签名列表 的拷贝副本 * * @return token签名列表 */ @@ -136,15 +140,20 @@ public class SaSession implements Serializable { } /** - * 返回token签名列表的拷贝副本,根据 device 筛选 + * 返回 Token 签名列表 的拷贝副本,根据 device 筛选 * * @param device 设备类型,填 null 代表不限设备类型 * @return token签名列表 */ public List tokenSignListCopyByDevice(String device) { + // 返回全部 + if(device == null) { + return tokenSignListCopy(); + } + // 返回筛选后的 List list = new ArrayList<>(); for (TokenSign tokenSign : tokenSignListCopy()) { - if(device == null || tokenSign.getDevice().equals(device)) { + if(tokenSign.getDevice().equals(device)) { list.add(tokenSign); } } @@ -152,10 +161,10 @@ public class SaSession implements Serializable { } /** - * 查找一个token签名 + * 查找一个 Token 签名 * * @param tokenValue token值 - * @return 查找到的tokenSign + * @return 查找到的 TokenSign */ public TokenSign getTokenSign(String tokenValue) { for (TokenSign tokenSign : tokenSignListCopy()) { @@ -167,16 +176,14 @@ public class SaSession implements Serializable { } /** - * 添加一个token签名 + * 添加一个 Token 签名 * - * @param tokenSign token签名 + * @param tokenSign Token 签名 */ public void addTokenSign(TokenSign tokenSign) { - // 如果已经存在于列表中,则无需再次添加 - for (TokenSign tokenSign2 : tokenSignListCopy()) { - if (tokenSign2.getValue().equals(tokenSign.getValue())) { - return; - } + // 如果已经存在于列表中,则无需再次添加 + if(getTokenSign(tokenSign.getValue()) != null) { + return; } // 添加并更新 tokenSignList.add(tokenSign); @@ -184,7 +191,7 @@ public class SaSession implements Serializable { } /** - * 添加一个token签名 + * 添加一个 Token 签名 * * @param tokenValue token值 * @param device 设备类型 @@ -194,9 +201,9 @@ public class SaSession implements Serializable { } /** - * 移除一个token签名 + * 移除一个 Token 签名 * - * @param tokenValue token名称 + * @param tokenValue token值 */ public void removeTokenSign(String tokenValue) { TokenSign tokenSign = getTokenSign(tokenValue); @@ -246,7 +253,7 @@ public class SaSession implements Serializable { } /** - * 修改此Session的最小剩余存活时间 (只有在Session的过期时间低于指定的minTimeout时才会进行修改) + * 修改此Session的最小剩余存活时间 (只有在 Session 的过期时间低于指定的 minTimeout 时才会进行修改) * @param minTimeout 过期时间 (单位: 秒) */ public void updateMinTimeout(long minTimeout) { @@ -258,7 +265,7 @@ public class SaSession implements Serializable { } /** - * 修改此Session的最大剩余存活时间 (只有在Session的过期时间高于指定的maxTimeout时才会进行修改) + * 修改此Session的最大剩余存活时间 (只有在 Session 的过期时间高于指定的 maxTimeout 时才会进行修改) * @param maxTimeout 过期时间 (单位: 秒) */ public void updateMaxTimeout(long maxTimeout) { @@ -420,12 +427,12 @@ public class SaSession implements Serializable { } /** - * 写值(只有在此key原本无值的时候才会写入) + * 写值 (只有在此 key 原本无值的情况下才会写入) * @param key 名称 * @param value 值 * @return 对象自身 */ - public SaSession setDefaultValue(String key, Object value) { + public SaSession setByNull(String key, Object value) { if(has(key) == false) { dataMap.put(key, value); update(); @@ -604,4 +611,20 @@ public class SaSession implements Serializable { return dataMap.keySet(); } + /** + *

此函数设计已过时,未来版本可能移除此类,请及时更换为: session.setByNull(),用法保持不变

+ * 写值(只有在此key原本无值的时候才会写入) + * @param key 名称 + * @param value 值 + * @return 对象自身 + */ + @Deprecated + public SaSession setDefaultValue(String key, Object value) { + if(has(key) == false) { + dataMap.put(key, value); + update(); + } + return this; + } + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/TokenSign.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/TokenSign.java index 4d65a980..298ee942 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/TokenSign.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/TokenSign.java @@ -5,75 +5,84 @@ import java.io.Serializable; /** * Token 签名 Model *

- * 挂在到SaSession上的token签名 + * 挂在到 SaSession 上的 Token 签名 * * @author kong */ public class TokenSign implements Serializable { - /** - * - */ - private static final long serialVersionUID = 1406115065849845073L; + /** + * + */ + private static final long serialVersionUID = 1406115065849845073L; - /** - * token值 - */ - private String value; + /** + * Token 值 + */ + private String value; - /** - * 所属设备类型 - */ - private String device; + /** + * 所属设备类型 + */ + private String device; - /** - * 构建一个 - */ - public TokenSign() { - } + /** + * 构建一个 + */ + public TokenSign() { + } - /** - * 构建一个 - * - * @param value token值 - * @param device 所属设备类型 - */ - public TokenSign(String value, String device) { - this.value = value; - this.device = device; - } + /** + * 构建一个 + * + * @param value Token 值 + * @param device 所属设备类型 + */ + public TokenSign(String value, String device) { + this.value = value; + this.device = device; + } - /** - * @return token值 - */ - public String getValue() { - return value; - } + /** + * @return Token 值 + */ + public String getValue() { + return value; + } - /** - * @return 所属设备类型 - */ - public String getDevice() { - return device; - } + /** + * @return 所属设备类型 + */ + public String getDevice() { + return device; + } - /** - * 反序列化需要 - */ - public void setValue(String value) { - this.value = value; - } + /** + * 写入 Token 值 + * + * @param value / + * @return 对象自身 + */ + public TokenSign setValue(String value) { + this.value = value; + return this; + } - /** - * 反序列化需要 - */ - public void setDevice(String device) { - this.device = device; - } + /** + * 写入所属设备类型 + * + * @param device / + * @return 对象自身 + */ + public TokenSign setDevice(String device) { + this.device = device; + return this; + } - @Override - public String toString() { - return "TokenSign [value=" + value + ", device=" + device + "]"; - } + // + @Override + public String toString() { + return "TokenSign [value=" + value + ", device=" + device + "]"; + } } From ba3b43dcbf515efa0854c2c8c333490f2fe4d794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E5=BF=98=E5=88=9D=E5=BF=83?= Date: Mon, 1 Aug 2022 05:01:47 +0000 Subject: [PATCH 057/144] update jpom domain --- sa-token-doc/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index f5c430d3..4cc7b177 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -372,7 +372,7 @@ - + From 8ba35dd32c3175cd061716a22daa7c11cd0715f6 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 1 Aug 2022 17:48:22 +0800 Subject: [PATCH 058/144] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=AE=98=E7=BD=91?= =?UTF-8?q?=E9=A6=96=E9=A1=B5=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/_sidebar.md | 1 + sa-token-doc/doc/more/join-group.md | 20 +++++++++++++ sa-token-doc/index.css | 46 ++++++++++++++++++----------- sa-token-doc/index.html | 25 ++++++---------- 4 files changed, 58 insertions(+), 34 deletions(-) create mode 100644 sa-token-doc/doc/more/join-group.md diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 5b50157f..3e3e024c 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -75,6 +75,7 @@ - [框架生态](/more/link) - [框架博客](/more/blog) - [推荐公众号](/more/tj-gzh) + - [加入讨论群](/more/join-group) - [赞助 Sa-Token](/more/sa-token-donate) - **附录** diff --git a/sa-token-doc/doc/more/join-group.md b/sa-token-doc/doc/more/join-group.md new file mode 100644 index 00000000..65a0f36a --- /dev/null +++ b/sa-token-doc/doc/more/join-group.md @@ -0,0 +1,20 @@ +# 加入讨论群 + +加入 Sa-Token 专属讨论群,与众多大佬一起努力 (huá shǔi) 成长 (mō yú)。 + +--- + +### 1、加入QQ交流群 + + +![QQ群](https://oss.dev33.cn/sa-token/qq-group-3.png ':size=180') + +QQ交流群:496757342 [点击加入](https://jq.qq.com/?_wv=1027&k=WNggbsFe) + +### 2、加入微信交流群: + +![微信群](https://oss.dev33.cn/sa-token/wx-qr-300.png ':size=180') + +(扫码添加微信,备注:sa-token,邀您加入群聊) + + diff --git a/sa-token-doc/index.css b/sa-token-doc/index.css index 7ca23902..5886d48b 100644 --- a/sa-token-doc/index.css +++ b/sa-token-doc/index.css @@ -2,6 +2,7 @@ /* 总 */ *{margin: 0px; padding: 0px;} body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica Neue","Arial,sans-serif";} +.z-div{} .s-width{width: 1000px; margin: auto;} /* 栏目标题 */ @@ -35,20 +36,17 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica .github-corner svg{color: #fff; fill: var(--theme-color, #42b983); height: 80px; width: 80px; z-index: 1001 !important;} -/* 手机端不显示广告,和一些其它东西 */ -@media (max-width: 576px) {.wwads-cn,.p-none{display:none!important}} - /* -------- 海报部分 --------- */ -.main-box{width: 100%; min-height: 100vh;; /* height: 80vh; */ text-align: center; background-image: url(https://oss.dev33.cn/sa-token/home-bg.jpg); } +.main-box{width: 100%; /* min-height: 70vh; */ /* height: 80vh; */ text-align: center; background-image: url(https://oss.dev33.cn/sa-token/home-bg.jpg); } .main-box{display: flex; align-items: center; text-align: center; } .fenge{min-height: 90px;} -.content-box{color: #000; flex: 1;} +.content-box{color: #000; flex: 1; padding: 120px 1em 70px;} .content-box h1{font-size: 100px; font-weight: 400; position: relative; margin-top: 40px; /* margin-top: 15vh; */} .content-box h1 small{font-size: 18px; position: absolute; bottom: 10px; margin-left: 5px; font-weight: 100;} /* .title-logo{width: 221px; cursor: pointer; transition: all 0.2s;} .title-logo:hover{transform: scale(1.2, 1.2);} */ -.sub-title{font-size: 22px; font-weight: 400; margin-top: 30px; margin-bottom: 25px; color: #6a8bad; color: #444;} +.sub-title{font-size: 22px; font-weight: 400; margin-top: 30px; margin-bottom: 25px; color: #6a8bad; color: #555;} /* .content-box p{line-height: 30px; padding: 0px 1em;} */ /* 角标位置修复 */ .badge-box a:nth-child(-n+2) img{position: relative; top: 1px;} @@ -63,12 +61,12 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica .btn-box{margin-top: 50px; margin-bottom: 40px;} .btn-box a{border: 1px #42B983 solid; border-radius: 2em; box-sizing: border-box; color: #3eaf7c; display: inline-block;transition: all 0.1s;} .btn-box a{font-size: 14px; background-color: rgba(0,255,0,0.04); letter-spacing: 1px; padding: 1em 2em; margin: 0 0.5em; margin-bottom: 14px; text-decoration: none; } +.btn-box a:hover{/* transform: scale(1.05, 1.05); */padding: 1em 2.3em; margin-left: 0.2em; margin-right: 0.2em;} /* 最后一个加深底色 */ -.btn-box a:last-child {color: #fff; background-color: #42B983; border: 1px green solid;} -.btn-box a:hover{/* transform: scale(1.05, 1.05); */padding: 1em 2.3em; margin: 0 0.2em;} +.btn-box .doc-btn {color: #fff; background-color: #42B983; border: 1px green solid;} /* 按钮发光动画 */ -.btn-box a:last-child{animation: bganimation 3s infinite;} +.btn-box .doc-btn{animation: bganimation 3s infinite;} @keyframes bganimation{ 0%{box-shadow: 0 0 1px #42B983;} 50%{box-shadow: 0 0 20px #42B983;} @@ -89,7 +87,7 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica .feature-z .s-title{font-size: 30px; font-weight: 400; margin-top: 70px; margin-bottom: 40px;} .feature-z{color: rgb(128, 128, 128); text-align: center; box-sizing: border-box; line-height: 24px; font-size: 16px;} -.feature-box{margin-top: 50px; margin-bottom: 70px; display: flex; flex-wrap: wrap; justify-content: space-between; /* justify-content: flex-start; */} +.feature-box{margin-top: 10px; margin-bottom: 70px; display: flex; flex-wrap: wrap; justify-content: space-between; /* justify-content: flex-start; */} .feature{border: 0px #000 solid; flex: 0 0 33%; text-align: left; padding: 1.8em 1.2em; box-sizing: border-box;} .feature h2{font-size: 22px; color: #000; font-weight: 400;} .feature p{margin-top: 14px; font-size: 16px; color: #4e6e8e;} @@ -105,8 +103,8 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica /* -------- 集成案例 --------- */ .s-case-box{justify-content: space-between;} -.s-case{border: 1px #eee solid; flex: 0 0 31.5%; margin-top: 30px; text-align: left; box-sizing: border-box; padding-bottom: 16px; overflow: hidden;} -.s-case{position: relative;} +.s-case{border: 1px #e5e5e5 solid; flex: 0 0 31.5%; margin-top: 30px; text-align: left; box-sizing: border-box; padding-bottom: 16px; overflow: hidden;} +.s-case{position: relative; transition: all 0.2s;} .s-case-link{display: block; width: 100%; height: 0px; padding-bottom: 50%; position: relative; overflow: hidden;} .s-case-link img{width: 100%; height: 100%; object-fit: cover; object-position: center; position: absolute;} .s-case-link img{transition: all 0.3s;} @@ -118,6 +116,7 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica /* 悬浮动画 */ +.s-case:hover{box-shadow: 0 0 20px #ccc;} .s-case:hover img{transform: scale(1.3, 1.3); } .s-case img:hover{cursor: pointer;} .s-case:hover .s-case-link:after {background-color: rgba(0, 0, 0, .35); color: #FFF;} @@ -173,7 +172,16 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica /* -------- 自适应 --------- */ -/* 媒体查询 */ +/* 一般的笔记本 */ +@media screen and (max-width: 1700px) { + .content-box{padding-top: 100px;} + .content-box h1{font-size: 80px;} + + /* 支持特性部分的间距 */ + .s-title.s-title-tx{margin-top: 50px; margin-bottom: 20px; /* display: none; */} +} + +/* 一般的手机 */ @media screen and (max-width: 800px) { .s-title{padding: 0 16px;} @@ -181,10 +189,10 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica .logo-box .logo-text,.copyright {display: none;} .main-box{ height: auto;} - .content-box{ padding: 2em 1em;} + .content-box{padding-top: 100px;} .content-box h1{font-size: 50px;} - .feature-z{padding: 0em;} + .feature-z{padding: 0em; padding-bottom: 50px;} .feature{min-width: 100%;} .com-box-f{padding: 0em;} @@ -199,11 +207,13 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica /* .s-header{position: static;} */ footer{position: static; line-height: 40px;} + + /* 手机端不显示广告,和一些其它东西 */ + .wwads-cn,.p-none{display:none!important} } -@media screen and (min-width: 1700px) { - .content-box h1{margin-top: 120px;} -} +/* 手机端不显示广告,和一些其它东西 */ +/* @media (max-width: 576px) {.wwads-cn,.p-none{display:none!important}} */ diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 4cc7b177..bff5a1a9 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -69,40 +69,33 @@

-

Sa-Token 支持特性

+

Sa-Token 支持特性

⚡️ 登录认证

@@ -372,7 +365,7 @@ - + From 0f530b73c23a2eb339fc211612bc0ade2ecd19ca Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 2 Aug 2022 08:33:37 +0800 Subject: [PATCH 059/144] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E6=8A=95=E7=A8=BF?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/lib/docsify-plugin.js | 2 +- sa-token-doc/doc/lib/index.css | 1 + sa-token-doc/doc/more/blog.md | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sa-token-doc/doc/lib/docsify-plugin.js b/sa-token-doc/doc/lib/docsify-plugin.js index 8e4c0e8a..cf2e86d1 100644 --- a/sa-token-doc/doc/lib/docsify-plugin.js +++ b/sa-token-doc/doc/lib/docsify-plugin.js @@ -27,7 +27,7 @@ var myDocsifyPlugin = function(hook, vm) { '' ].join(''); return html + footer; diff --git a/sa-token-doc/doc/lib/index.css b/sa-token-doc/doc/lib/index.css index 64578e98..fa1b6797 100644 --- a/sa-token-doc/doc/lib/index.css +++ b/sa-token-doc/doc/lib/index.css @@ -75,6 +75,7 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu .sidebar .sidebar-nav>ul>li> strong{font-size: 1.2em; margin-top: 10px;} /* .sidebar ul li a{color: #222;} */ .sidebar .sidebar-nav>ul>li>ul>li>a{/* color: #222; */font-size: 16px; /* font-weight: 700; */} +.main-box .sidebar ul li a{color: #00323c;} /* 做到悬浮出现下划线的效果 */ .main-box .sidebar>.sidebar-nav>ul{padding-left: 6px;} diff --git a/sa-token-doc/doc/more/blog.md b/sa-token-doc/doc/more/blog.md index 5051be33..7e342913 100644 --- a/sa-token-doc/doc/more/blog.md +++ b/sa-token-doc/doc/more/blog.md @@ -1,7 +1,7 @@ # 框架博客 -> 此页面收集 Sa-Token 相关技术文章,欢迎大家投稿(不限平台), -> 直接提交 [轻量级pr](https://gitee.com/dromara/sa-token/tree/dev/sa-token-doc/doc/more/blog.md) 即可(按照发表日期倒叙)。 +> 此页面收集 Sa-Token 相关技术文章,欢迎大家投稿(不限平台,按照发表日期倒叙), +> [投稿链接](https://wj.qq.com/s2/10596458/aa96/) --- From d3af3332a2e5bc981c60037c3922f25c2b60fb97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=B0=91=E5=90=8C=E5=AD=A6?= <42923411+dengyumin@users.noreply.github.com> Date: Wed, 3 Aug 2022 20:04:34 +0800 Subject: [PATCH 060/144] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E9=94=99?= =?UTF-8?q?=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/use/at-check.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/use/at-check.md b/sa-token-doc/doc/use/at-check.md index 9daa9cab..af26b14e 100644 --- a/sa-token-doc/doc/use/at-check.md +++ b/sa-token-doc/doc/use/at-check.md @@ -34,7 +34,7 @@ public class SaTokenConfigure implements WebMvcConfigurer { ``` 保证此类被`springboot`启动类扫描到即可 -!> 注意:如果在高版本 `SpringBoot (≥2.6.x)` 下注册拦截器生效,则需要额外添加 `@EnableWebMvc` 注解才可以使用。 +!> 注意:如果在高版本 `SpringBoot (≥2.6.x)` 下注册拦截器失效,则需要额外添加 `@EnableWebMvc` 注解才可以使用。 ### 2、使用注解鉴权 From f6fccfb8469f2eb7fbefe49f122af8a4b7c6e282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=94=E6=98=8E?= <2393584716@qq.com> Date: Sun, 7 Aug 2022 02:21:22 +0000 Subject: [PATCH 061/144] update sa-token-doc/doc/fun/sa-token-test.md. --- sa-token-doc/doc/fun/sa-token-test.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/fun/sa-token-test.md b/sa-token-doc/doc/fun/sa-token-test.md index f5cc2af5..8472be65 100644 --- a/sa-token-doc/doc/fun/sa-token-test.md +++ b/sa-token-doc/doc/fun/sa-token-test.md @@ -2,5 +2,5 @@ --- -此份考卷将测评您对Sa-Token框架的掌握程度(满分100),链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) +此份考卷将测评您对Sa-Token框架的掌握程度(满分100),- 链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) From 36702fcd60d8365b6b47f6f4f94329e5e54d75b7 Mon Sep 17 00:00:00 2001 From: RockMan <985449475@qq.com> Date: Sun, 7 Aug 2022 02:21:40 +0000 Subject: [PATCH 062/144] update sa-token-doc/doc/fun/sa-token-test.md. --- sa-token-doc/doc/fun/sa-token-test.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/fun/sa-token-test.md b/sa-token-doc/doc/fun/sa-token-test.md index 8472be65..ea64c574 100644 --- a/sa-token-doc/doc/fun/sa-token-test.md +++ b/sa-token-doc/doc/fun/sa-token-test.md @@ -2,5 +2,5 @@ --- -此份考卷将测评您对Sa-Token框架的掌握程度(满分100),- 链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) +此份考卷将测评您对Sa-Token框架的掌握程度(满分100),-- 链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) From 636726f4ee6f14a05362364df1705bb35e3bdd22 Mon Sep 17 00:00:00 2001 From: RockMan <985449475@qq.com> Date: Sun, 7 Aug 2022 02:23:38 +0000 Subject: [PATCH 063/144] update sa-token-doc/doc/fun/sa-token-test.md. --- sa-token-doc/doc/fun/sa-token-test.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/fun/sa-token-test.md b/sa-token-doc/doc/fun/sa-token-test.md index ea64c574..a244185a 100644 --- a/sa-token-doc/doc/fun/sa-token-test.md +++ b/sa-token-doc/doc/fun/sa-token-test.md @@ -2,5 +2,5 @@ --- -此份考卷将测评您对Sa-Token框架的掌握程度(满分100),-- 链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) +此份考卷将测评您对Sa-Token框架的掌握程度(满分100),--- 链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) From 84a8a28bc31c5b1d4e567eb4c6574cd606f6f4c8 Mon Sep 17 00:00:00 2001 From: RockMan <985449475@qq.com> Date: Sun, 7 Aug 2022 02:25:07 +0000 Subject: [PATCH 064/144] update sa-token-doc/doc/fun/sa-token-test.md. --- sa-token-doc/doc/fun/sa-token-test.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/fun/sa-token-test.md b/sa-token-doc/doc/fun/sa-token-test.md index a244185a..af9e8b43 100644 --- a/sa-token-doc/doc/fun/sa-token-test.md +++ b/sa-token-doc/doc/fun/sa-token-test.md @@ -2,5 +2,5 @@ --- -此份考卷将测评您对Sa-Token框架的掌握程度(满分100),--- 链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) +此份考卷将测评您对Sa-Token框架的掌握程度(满分100),---- 链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) From 6825f662cf5bcd3b01362f8a6f3930e61df635c5 Mon Sep 17 00:00:00 2001 From: RockMan <985449475@qq.com> Date: Sun, 7 Aug 2022 02:27:37 +0000 Subject: [PATCH 065/144] update sa-token-doc/doc/fun/sa-token-test.md. --- sa-token-doc/doc/fun/sa-token-test.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/fun/sa-token-test.md b/sa-token-doc/doc/fun/sa-token-test.md index af9e8b43..f5cc2af5 100644 --- a/sa-token-doc/doc/fun/sa-token-test.md +++ b/sa-token-doc/doc/fun/sa-token-test.md @@ -2,5 +2,5 @@ --- -此份考卷将测评您对Sa-Token框架的掌握程度(满分100),---- 链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) +此份考卷将测评您对Sa-Token框架的掌握程度(满分100),链接:[https://ks.wjx.top/vj/wFKPziD.aspx](https://ks.wjx.top/vj/wFKPziD.aspx) From 7ce9ad7a9a67d5c3a65b6e26d7d1591ac2908b1c Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 7 Aug 2022 18:27:38 +0800 Subject: [PATCH 066/144] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=83=8C=E6=99=AF?= =?UTF-8?q?=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/sso/sso-pro.md | 2 +- sa-token-doc/index.css | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/sa-token-doc/doc/sso/sso-pro.md b/sa-token-doc/doc/sso/sso-pro.md index 15ab62a1..d64cec21 100644 --- a/sa-token-doc/doc/sso/sso-pro.md +++ b/sa-token-doc/doc/sso/sso-pro.md @@ -33,7 +33,7 @@ Sa-Sso-Pro 并非随意收费,只有当您的系统需要 **统一认证中心** 时您才会用到它,花一笔小钱节省大量开发工期,整体来看,这是非常划算的。 -另外:即使您没有购买 `Sa-Sso-Pro`,也不会影响到您对 `Sa-Token` 的使用,举个例子:MySql具有社区版与企业版,即使您没有购买其付费版,也不会影响到您对免费 MySql 的使用。 +另外:即使您没有购买 `Sa-Sso-Pro`,也不会影响到您对 `Sa-Token` 的使用,举个例子:MySQL具有社区版与企业版,即使您没有购买其付费版,也不会影响到您对免费 MySql 的使用。 diff --git a/sa-token-doc/index.css b/sa-token-doc/index.css index 5886d48b..baccfa30 100644 --- a/sa-token-doc/index.css +++ b/sa-token-doc/index.css @@ -37,7 +37,7 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica /* -------- 海报部分 --------- */ -.main-box{width: 100%; /* min-height: 70vh; */ /* height: 80vh; */ text-align: center; background-image: url(https://oss.dev33.cn/sa-token/home-bg.jpg); } +.main-box{width: 100%; /* min-height: 70vh; */ /* height: 80vh; */ text-align: center; } .main-box{display: flex; align-items: center; text-align: center; } .fenge{min-height: 90px;} .content-box{color: #000; flex: 1; padding: 120px 1em 70px;} @@ -46,21 +46,23 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica /* .title-logo{width: 221px; cursor: pointer; transition: all 0.2s;} .title-logo:hover{transform: scale(1.2, 1.2);} */ -.sub-title{font-size: 22px; font-weight: 400; margin-top: 30px; margin-bottom: 25px; color: #6a8bad; color: #555;} +.sub-title{font-size: 22px; font-weight: 400; margin-top: 30px; margin-bottom: 25px; color: #6a8bad; color: #234;} /* .content-box p{line-height: 30px; padding: 0px 1em;} */ /* 角标位置修复 */ .badge-box a:nth-child(-n+2) img{position: relative; top: 1px;} -.main-box{animation: changes 60s 0.2s linear infinite normal; background-attachment: ;} /* normal | alternate */ +/* .main-box{background-image: url(https://oss.dev33.cn/sa-token/home-bg.jpg);} */ +.main-box{background-image: url(https://oss.dev33.cn/sa-token/home-bg3.png); background-size: 120% 100%;} +.main-box{animation: changes 30s 0.2s linear infinite normal; /* background-attachment: ; */} /* normal | alternate */ @keyframes changes { from {background-position: 0vw 0%;} - to {background-position: -100vw 0%;} + to {background-position: -20vw 0%;} } /* 几个按钮 */ .btn-box{margin-top: 50px; margin-bottom: 40px;} -.btn-box a{border: 1px #42B983 solid; border-radius: 2em; box-sizing: border-box; color: #3eaf7c; display: inline-block;transition: all 0.1s;} -.btn-box a{font-size: 14px; background-color: rgba(0,255,0,0.04); letter-spacing: 1px; padding: 1em 2em; margin: 0 0.5em; margin-bottom: 14px; text-decoration: none; } +.btn-box a{border: 1px #1e8f5c solid; border-radius: 2em; box-sizing: border-box; color: #1e8f5c; display: inline-block;transition: all 0.1s;} +.btn-box a{font-size: 14px; background-color: rgba(0,255,0,0.06); letter-spacing: 1px; padding: 1em 2em; margin: 0 0.5em; margin-bottom: 14px; text-decoration: none; } .btn-box a:hover{/* transform: scale(1.05, 1.05); */padding: 1em 2.3em; margin-left: 0.2em; margin-right: 0.2em;} /* 最后一个加深底色 */ .btn-box .doc-btn {color: #fff; background-color: #42B983; border: 1px green solid;} From 83ce6fcfd3e9caf7efdc7be7c13b0df26a808da0 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 7 Aug 2022 22:19:42 +0800 Subject: [PATCH 067/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index bff5a1a9..2f3fea21 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -610,7 +610,7 @@ } if(window.innerWidth > 1800) { if(navigator.userAgent.indexOf('WebKit') > -1) { - f5ImgSize(); + // f5ImgSize(); } } From 42272c83b61056ebfe167abacbc9daa93ba9127c Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 02:47:37 +0800 Subject: [PATCH 068/144] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E6=A8=A1=E5=BC=8F=E4=B8=8B=E4=B8=8D=E8=83=BD=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E9=87=8D=E7=BD=AE=20StpLogic=20=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/dev33/satoken/SaManager.java | 2 +- .../main/java/cn/dev33/satoken/stp/StpUtil.java | 16 +++++++++++----- .../java/com/pj/satoken/at/StpUserUtil.java | 17 +++++++++++------ .../java/com/pj/satoken/at/StpUserUtil.java | 17 +++++++++++------ 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java index e23e9e31..cc089c86 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java @@ -236,7 +236,7 @@ public class SaManager { return StpUtil.stpLogic; } - // 从SaManager中获取 + // 从 stpLogicMap 中获取 StpLogic stpLogic = stpLogicMap.get(loginType); if(stpLogic == null) { /* diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index 40a06293..79984d91 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -32,12 +32,18 @@ public class StpUtil { /** * 重置 StpLogic 对象 - * @param stpLogic / + *
1、更改此账户的 StpLogic 对象 + *
2、put 到全局 StpLogic 集合中 + * + * @param newStpLogic / */ - public static void setStpLogic(StpLogic stpLogic) { - StpUtil.stpLogic = stpLogic; - // 防止自定义 stpLogic 被覆盖 - SaManager.putStpLogic(stpLogic); + public static void setStpLogic(StpLogic newStpLogic) { + // 重置此账户的 StpLogic 对象 + stpLogic = newStpLogic; + + // 添加到全局 StpLogic 集合中 + // 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic + SaManager.putStpLogic(newStpLogic); } diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java index 939b5fe8..eeb3945c 100644 --- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java +++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java @@ -8,7 +8,6 @@ import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpLogic; -import cn.dev33.satoken.stp.StpUtil; /** * Sa-Token 权限认证工具类 (user版) @@ -36,12 +35,18 @@ public class StpUserUtil { /** * 重置 StpLogic 对象 - * @param stpLogic / + *
1、更改此账户的 StpLogic 对象 + *
2、put 到全局 StpLogic 集合中 + * + * @param newStpLogic / */ - public static void setStpLogic(StpLogic stpLogic) { - StpUtil.stpLogic = stpLogic; - // 防止自定义 stpLogic 被覆盖 - SaManager.putStpLogic(stpLogic); + public static void setStpLogic(StpLogic newStpLogic) { + // 重置此账户的 StpLogic 对象 + stpLogic = newStpLogic; + + // 添加到全局 StpLogic 集合中 + // 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic + SaManager.putStpLogic(newStpLogic); } diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java index 939b5fe8..eeb3945c 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java @@ -8,7 +8,6 @@ import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpLogic; -import cn.dev33.satoken.stp.StpUtil; /** * Sa-Token 权限认证工具类 (user版) @@ -36,12 +35,18 @@ public class StpUserUtil { /** * 重置 StpLogic 对象 - * @param stpLogic / + *
1、更改此账户的 StpLogic 对象 + *
2、put 到全局 StpLogic 集合中 + * + * @param newStpLogic / */ - public static void setStpLogic(StpLogic stpLogic) { - StpUtil.stpLogic = stpLogic; - // 防止自定义 stpLogic 被覆盖 - SaManager.putStpLogic(stpLogic); + public static void setStpLogic(StpLogic newStpLogic) { + // 重置此账户的 StpLogic 对象 + stpLogic = newStpLogic; + + // 添加到全局 StpLogic 集合中 + // 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic + SaManager.putStpLogic(newStpLogic); } From c4c88105c069d039165075d172222900885c5c75 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 03:33:04 +0800 Subject: [PATCH 069/144] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20SaSession=20?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E4=B8=AD=20TokenSign=20=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E6=9C=89=E5=8F=AF=E8=83=BD=E7=A9=BA=E6=8C=87=E9=92=88=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/dev33/satoken/session/SaSession.java | 4 ++-- .../src/main/java/cn/dev33/satoken/util/SaFoxUtil.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index 5f25f1d0..e9be637a 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -153,7 +153,7 @@ public class SaSession implements Serializable { // 返回筛选后的 List list = new ArrayList<>(); for (TokenSign tokenSign : tokenSignListCopy()) { - if(tokenSign.getDevice().equals(device)) { + if(SaFoxUtil.equals(tokenSign.getDevice(), device)) { list.add(tokenSign); } } @@ -168,7 +168,7 @@ public class SaSession implements Serializable { */ public TokenSign getTokenSign(String tokenValue) { for (TokenSign tokenSign : tokenSignListCopy()) { - if (tokenSign.getValue().equals(tokenValue)) { + if (SaFoxUtil.equals(tokenSign.getValue(), tokenValue)) { return tokenSign; } } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java index 62765b86..be672192 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java @@ -75,6 +75,16 @@ public class SaFoxUtil { return isEmpty(str) == false; } + /** + * 比较两个对象是否相等 + * @param a 第一个对象 + * @param b 第二个对象 + * @return 两个对象是否相等 + */ + public static boolean equals(Object a, Object b) { + return (a == b) || (a != null && a.equals(b)); + } + /** * 以当前时间戳和随机int数字拼接一个随机字符串 * From a2ec360aef3c8bf125b5a12e6490394b8ba013de Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 15:05:45 +0800 Subject: [PATCH 070/144] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=BD=93=E6=9D=83?= =?UTF-8?q?=E9=99=90=E7=A0=81=E4=B8=BAnull=E6=97=B6=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E5=B8=A6=E6=9D=A5=E7=9A=84=E7=A9=BA=E6=8C=87=E9=92=88=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/dev33/satoken/session/SaSession.java | 4 ++-- .../main/java/cn/dev33/satoken/util/SaFoxUtil.java | 13 +++++++++++-- .../java/cn/dev33/satoken/util/SaFoxUtilTest.java | 3 +++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index e9be637a..734e8d65 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -111,13 +111,13 @@ public class SaSession implements Serializable { /** * 此 Session 绑定的 Token 签名列表 */ - private Vector tokenSignList = new Vector<>(); + private List tokenSignList = new Vector<>(); /** * 写入此 Session 绑定的 Token 签名列表 * @param tokenSignList Token 签名列表 */ - public void setTokenSignList(Vector tokenSignList) { + public void setTokenSignList(List tokenSignList) { this.tokenSignList = tokenSignList; } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java index be672192..cf259aaa 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java @@ -168,13 +168,22 @@ public class SaFoxUtil { * @return 是否可以匹配 */ public static boolean vagueMatch(String patt, String str) { - // 如果表达式不带有*号,则只需简单equals即可 (速度提升200倍) + // 两者均为 null 时,直接返回 true + if(patt == null && str == null) { + return true; + } + // 两者其一为 null 时,直接返回 false + if(patt == null || str == null) { + return false; + } + // 如果表达式不带有*号,则只需简单equals即可 (这样可以使速度提升200倍左右) if(patt.indexOf("*") == -1) { return patt.equals(str); } + // 正则匹配 return Pattern.matches(patt.replaceAll("\\*", ".*"), str); } - + /** * 将指定值转化为指定类型 * @param 泛型 diff --git a/sa-token-test/sa-token-core-test/src/test/java/cn/dev33/satoken/util/SaFoxUtilTest.java b/sa-token-test/sa-token-core-test/src/test/java/cn/dev33/satoken/util/SaFoxUtilTest.java index e97affed..d7cca62c 100644 --- a/sa-token-test/sa-token-core-test/src/test/java/cn/dev33/satoken/util/SaFoxUtilTest.java +++ b/sa-token-test/sa-token-core-test/src/test/java/cn/dev33/satoken/util/SaFoxUtilTest.java @@ -71,6 +71,9 @@ public class SaFoxUtilTest { Assertions.assertTrue(SaFoxUtil.vagueMatch("hello*", "hello world")); Assertions.assertFalse(SaFoxUtil.vagueMatch("hello*", "he")); Assertions.assertTrue(SaFoxUtil.vagueMatch("hello*", "hello*")); + Assertions.assertTrue(SaFoxUtil.vagueMatch(null, null)); + Assertions.assertFalse(SaFoxUtil.vagueMatch(null, "hello")); + Assertions.assertFalse(SaFoxUtil.vagueMatch("hello*", null)); } @Test From cd909f4137f4c6ee2c75ee83ecd4173ad018c7fd Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 16:38:55 +0800 Subject: [PATCH 071/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20`StpUtil.getExtra(?= =?UTF-8?q?tokenValue,=20key)`=20=E6=96=B9=E6=B3=95=EF=BC=8C=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E8=8E=B7=E5=8F=96=E4=BB=BB=E6=84=8F=20token=20?= =?UTF-8?q?=E7=9A=84=E6=89=A9=E5=B1=95=E5=8F=82=E6=95=B0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/dev33/satoken/stp/StpLogic.java | 12 +++++++++++- .../src/main/java/cn/dev33/satoken/stp/StpUtil.java | 12 +++++++++++- .../cn/dev33/satoken/jwt/StpLogicJwtForMixin.java | 12 ++++++++++-- .../cn/dev33/satoken/jwt/StpLogicJwtForSimple.java | 12 ++++++++++-- .../dev33/satoken/jwt/StpLogicJwtForStateless.java | 12 ++++++++++-- .../src/test/java/com/pj/test/JwtForMixinTest.java | 7 +++++-- .../src/test/java/com/pj/test/JwtForSimpleTest.java | 6 ++++-- .../test/java/com/pj/test/JwtForStatelessTest.java | 3 +++ 8 files changed, 64 insertions(+), 12 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 7a0ddb7c..fd323d90 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -743,13 +743,23 @@ public class StpLogic { } /** - * 获取Token扩展信息(只在jwt模式下有效) + * 获取当前 Token 的扩展信息(此函数只在jwt模式下生效) * @param key 键值 * @return 对应的扩展数据 */ public Object getExtra(String key) { throw new ApiDisabledException(); } + + /** + * 获取指定 Token 的扩展信息(此函数只在jwt模式下生效) + * @param tokenValue 指定的 Token 值 + * @param key 键值 + * @return 对应的扩展数据 + */ + public Object getExtra(String tokenValue, String key) { + throw new ApiDisabledException(); + } // ---- 其它操作 diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index 79984d91..3e24922f 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -313,13 +313,23 @@ public class StpUtil { } /** - * 获取Token扩展信息(只在jwt模式下有效) + * 获取当前 Token 的扩展信息(此函数只在jwt模式下生效) * @param key 键值 * @return 对应的扩展数据 */ public static Object getExtra(String key) { return stpLogic.getExtra(key); } + + /** + * 获取指定 Token 的扩展信息(此函数只在jwt模式下生效) + * @param tokenValue 指定的 Token 值 + * @param key 键值 + * @return 对应的扩展数据 + */ + public static Object getExtra(String tokenValue, String key) { + return stpLogic.getExtra(tokenValue, key); + } // =================== User-Session 相关 =================== diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java index b4afc679..8aa555bb 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java @@ -150,11 +150,19 @@ public class StpLogicJwtForMixin extends StpLogic { } /** - * 获取Token携带的扩展信息 + * 获取当前 Token 的扩展信息 */ @Override public Object getExtra(String key) { - return SaJwtUtil.getPayloads(getTokenValue(), loginType, jwtSecretKey()).get(key); + return getExtra(getTokenValue(), key); + } + + /** + * 获取指定 Token 的扩展信息 + */ + @Override + public Object getExtra(String tokenValue, String key) { + return SaJwtUtil.getPayloads(tokenValue, loginType, jwtSecretKey()).get(key); } /** diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForSimple.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForSimple.java index ccb3f9b5..6605bb9e 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForSimple.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForSimple.java @@ -49,11 +49,19 @@ public class StpLogicJwtForSimple extends StpLogic { } /** - * 获取Token携带的扩展信息 + * 获取当前 Token 的扩展信息 */ @Override public Object getExtra(String key) { - return SaJwtUtil.getPayloadsNotCheck(getTokenValue(), loginType, jwtSecretKey()).get(key); + return getExtra(getTokenValue(), key); + } + + /** + * 获取指定 Token 的扩展信息 + */ + @Override + public Object getExtra(String tokenValue, String key) { + return SaJwtUtil.getPayloadsNotCheck(tokenValue, loginType, jwtSecretKey()).get(key); } } diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java index 43bee718..755d1eca 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java @@ -138,11 +138,19 @@ public class StpLogicJwtForStateless extends StpLogic { } /** - * 获取Token携带的扩展信息 + * 获取当前 Token 的扩展信息 */ @Override public Object getExtra(String key) { - return SaJwtUtil.getPayloads(getTokenValue(), loginType, jwtSecretKey()).get(key); + return getExtra(getTokenValue(), key); + } + + /** + * 获取指定 Token 的扩展信息 + */ + @Override + public Object getExtra(String tokenValue, String key) { + return SaJwtUtil.getPayloads(tokenValue, loginType, jwtSecretKey()).get(key); } diff --git a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java index 0c9c3c31..ef6ed9e2 100644 --- a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java +++ b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java @@ -38,14 +38,14 @@ public class JwtForMixinTest { // 开始 @BeforeAll public static void beforeClass() { - System.out.println("\n\n------------------------ JwtForMixTest star ..."); + System.out.println("\n\n------------------------ JwtForMixinTest star ..."); StpUtil.setStpLogic(new StpLogicJwtForMixin()); } // 结束 @AfterAll public static void afterClass() { - System.out.println("\n\n------------------------ JwtForMixTest end ... \n"); + System.out.println("\n\n------------------------ JwtForMixinTest end ... \n"); } // 测试:登录 @@ -261,9 +261,12 @@ public class JwtForMixinTest { public void getExtra() { // 登录 StpUtil.login(10001, SaLoginConfig.setExtra("name", "zhangsan")); + String tokenValue = StpUtil.getTokenValue(); // 可以取到 Assertions.assertEquals(StpUtil.getExtra("name"), "zhangsan"); + Assertions.assertEquals(StpUtil.getExtra(tokenValue, "name"), "zhangsan"); + // 取不到 Assertions.assertEquals(StpUtil.getExtra("name2"), null); } diff --git a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForSimpleTest.java b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForSimpleTest.java index 88c31e2a..0e04ecf8 100644 --- a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForSimpleTest.java +++ b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForSimpleTest.java @@ -32,7 +32,7 @@ public class JwtForSimpleTest { // 开始 @BeforeAll public static void beforeClass() { - System.out.println("\n\n------------------------ JwtForStyleTest star ..."); + System.out.println("\n\n------------------------ JwtForSimpleTest star ..."); dao = SaManager.getSaTokenDao(); StpUtil.setStpLogic(new StpLogicJwtForSimple()); } @@ -40,7 +40,7 @@ public class JwtForSimpleTest { // 结束 @AfterAll public static void afterClass() { - System.out.println("\n\n------------------------ JwtForStyleTest end ... \n"); + System.out.println("\n\n------------------------ JwtForSimpleTest end ... \n"); } // 测试:登录 @@ -76,9 +76,11 @@ public class JwtForSimpleTest { public void getExtra() { // 登录 StpUtil.login(10001, SaLoginConfig.setExtra("name", "zhangsan")); + String tokenValue = StpUtil.getTokenValue(); // 可以取到 Assertions.assertEquals(StpUtil.getExtra("name"), "zhangsan"); + Assertions.assertEquals(StpUtil.getExtra(tokenValue, "name"), "zhangsan"); // 取不到 Assertions.assertEquals(StpUtil.getExtra("name2"), null); } diff --git a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForStatelessTest.java b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForStatelessTest.java index 43a123c7..78793fea 100644 --- a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForStatelessTest.java +++ b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForStatelessTest.java @@ -170,9 +170,12 @@ public class JwtForStatelessTest { public void getExtra() { // 登录 StpUtil.login(10001, SaLoginConfig.setExtra("name", "zhangsan")); + String tokenValue = StpUtil.getTokenValue(); // 可以取到 Assertions.assertEquals(StpUtil.getExtra("name"), "zhangsan"); + Assertions.assertEquals(StpUtil.getExtra(tokenValue, "name"), "zhangsan"); + // 取不到 Assertions.assertEquals(StpUtil.getExtra("name2"), null); } From 386295dc6bda134065e9f22c3aadba3f3361724b Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 17:31:13 +0800 Subject: [PATCH 072/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20`SaOAuth2Util.chec?= =?UTF-8?q?kClientTokenScope(clientToken,=20scopes)`=20=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=8C=E6=A0=A1=E9=AA=8C=20Client-Token=20=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=90=AB=E6=9C=89=E6=8C=87=E5=AE=9A=20Scope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/oauth2/logic/SaOAuth2Template.java | 15 +++++++++++++++ .../dev33/satoken/oauth2/logic/SaOAuth2Util.java | 11 ++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java index 0e7b4d3a..16bdcf83 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java @@ -98,6 +98,21 @@ public class SaOAuth2Template { SaOAuth2Exception.throwBy(scopeList.contains(scope) == false, "该 Access-Token 不具备 Scope:" + scope); } } + /** + * 校验:指定 Client-Token 是否具有指定 Scope + * @param clientToken Client-Token + * @param scopes 需要校验的权限列表 + */ + public void checkClientTokenScope(String clientToken, String... scopes) { + if(scopes == null || scopes.length == 0) { + return; + } + ClientTokenModel ct = checkClientToken(clientToken); + List scopeList = SaFoxUtil.convertStringToList(ct.scope); + for (String scope : scopes) { + SaOAuth2Exception.throwBy(scopeList.contains(scope) == false, "该 Client-Token 不具备 Scope:" + scope); + } + } // ------------------- generate 构建数据 /** diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java index 1f78e97d..25004650 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java @@ -49,7 +49,7 @@ public class SaOAuth2Util { public static ClientTokenModel checkClientToken(String clientToken) { return saOAuth2Template.checkClientToken(clientToken); } - + /** * 获取 Access-Token 所代表的LoginId * @param accessToken Access-Token @@ -68,6 +68,15 @@ public class SaOAuth2Util { saOAuth2Template.checkScope(accessToken, scopes); } + /** + * 校验:指定 Client-Token 是否具有指定 Scope + * @param clientToken Client-Token + * @param scopes 需要校验的权限列表 + */ + public static void checkClientTokenScope(String clientToken, String... scopes) { + saOAuth2Template.checkClientTokenScope(clientToken, scopes); + } + // ------------------- generate 构建数据 /** From 09c7372513d6518a22f2d9ddfaa215aa66d5da28 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 17:46:35 +0800 Subject: [PATCH 073/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index fd323d90..aadac3e6 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -319,6 +319,7 @@ public class StpLogic { // 如果配置为共享token, 则尝试从Session签名记录里取出token if(getConfigOfIsShare()) { // 为确保 jwt-simple 模式的 token Extra 数据生成不受旧token影响,这里必须确保 is-share 配置项在 ExtraData 为空时才可以生效 + // 即:在 login 时提供了 Extra 数据后,即使配置了 is-share=true 也不能复用旧 Token,必须创建新 Token if(loginModel.getExtraData() == null || loginModel.getExtraData().size() == 0) { tokenValue = getTokenValueByLoginId(id, loginModel.getDeviceOrDefault()); } From c6c0c697328287b60d59c9c9e1f356ccd086769b Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 17:47:00 +0800 Subject: [PATCH 074/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A4=9A=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E6=A8=A1=E5=BC=8F=E4=B8=8B=E9=9B=86=E6=88=90jwt?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E7=9A=84=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/plugin/jwt-extend.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sa-token-doc/doc/plugin/jwt-extend.md b/sa-token-doc/doc/plugin/jwt-extend.md index e1cfad82..c801c904 100644 --- a/sa-token-doc/doc/plugin/jwt-extend.md +++ b/sa-token-doc/doc/plugin/jwt-extend.md @@ -167,8 +167,7 @@ sa-token-jwt 插件默认只为 `StpUtil` 注入 `StpLogicJwtFoxXxx` 实现, */ @Autowired public void setUserStpLogic() { - StpUserUtil.stpLogic = new StpLogicJwtForSimple(StpUserUtil.TYPE); - SaManager.putStpLogic(StpUserUtil.stpLogic); + StpUserUtil.setStpLogic(new StpLogicJwtForSimple(StpUserUtil.TYPE)); } ``` From b7eb24f07edc9953d2bc5f2011a255bdfaeb2a59 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 23:03:58 +0800 Subject: [PATCH 075/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/plugin/jwt-extend.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sa-token-doc/doc/plugin/jwt-extend.md b/sa-token-doc/doc/plugin/jwt-extend.md index c801c904..358ed480 100644 --- a/sa-token-doc/doc/plugin/jwt-extend.md +++ b/sa-token-doc/doc/plugin/jwt-extend.md @@ -154,6 +154,9 @@ StpUtil.login(10001, SaLoginConfig // 获取扩展参数 String name = StpUtil.getExtra("name"); + +// 获取任意 Token 的扩展参数 +String name = StpUtil.getExtra("tokenValue", "name"); ``` @@ -173,5 +176,3 @@ public void setUserStpLogic() { - - From 30f8d0d5d5d43408a69609b6a22d9f461d4733fb Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 23:05:00 +0800 Subject: [PATCH 076/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=20`SaSsoHandle.check?= =?UTF-8?q?Ticket(ticket,=20currUri);`=20=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E4=BD=BF=E5=85=B6=E4=B8=8D=E6=8F=90=E4=BE=9B=20currUri=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=97=B6=E5=B0=86=E4=B8=8D=E5=86=8D=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E5=8D=95=E7=82=B9=E6=B3=A8=E9=94=80=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java index 8a864d43..4ad7ebf9 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java @@ -363,7 +363,7 @@ public class SaSsoHandle { if(cfg.getIsHttp()) { // 模式三:使用 http 请求从认证中心校验ticket String ssoLogoutCall = null; - if(cfg.getIsSlo()) { + if(cfg.getIsSlo() && SaFoxUtil.isNotEmpty(currUri)) { ssoLogoutCall = SaHolder.getRequest().getUrl().replace(currUri, Api.ssoLogoutCall); } From e3a458d899423f8b15e0bf25b46659b248343e9e Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 23:48:57 +0800 Subject: [PATCH 077/144] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=8B=E8=B8=A2=E4=BA=BA=E4=B8=8B=E4=BC=9A?= =?UTF-8?q?=E6=8A=9B=E5=87=BA=E5=BC=82=E5=B8=B8=20`=E9=9D=9EWeb=E4=B8=8A?= =?UTF-8?q?=E4=B8=8B=E6=96=87=E6=97=A0=E6=B3=95=E8=8E=B7=E5=8F=96Request`?= =?UTF-8?q?=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/dev33/satoken/stp/StpLogic.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index aadac3e6..0b422bf0 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -371,21 +371,24 @@ public class StpLogic { * 会话注销 */ public void logout() { - // 如果连token都没有,那么无需执行任何操作 + // 如果连 Token 都没有,那么无需执行任何操作 String tokenValue = getTokenValue(); if(SaFoxUtil.isEmpty(tokenValue)) { return; } - // 从当前 [storage存储器] 里删除 + // 从当前 [Storage存储器] 里删除 SaHolder.getStorage().delete(splicingKeyJustCreatedSave()); - // 如果打开了Cookie模式,则把cookie清除掉 + // 如果打开了 Cookie 模式,则把 Cookie 清除掉 if(getConfig().getIsReadCookie()){ SaHolder.getResponse().deleteCookie(getTokenName()); } + + // 清除当前上下文的 [临时有效期check标记] + SaHolder.getStorage().delete(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY); - // 清除这个token的相关信息 + // 清除这个token的相关信息 logoutByTokenValue(tokenValue); } @@ -469,16 +472,16 @@ public class StpLogic { // 2. 注销 Token-Session deleteTokenSession(tokenValue); - // if. 无效 loginId 立即返回 + // 3. 清理 token -> id 索引 String loginId = getLoginIdNotHandle(tokenValue); + if(loginId != null) { + deleteTokenToIdMapping(tokenValue); + } + + // if. 无效 loginId 立即返回 if(isValidLoginId(loginId) == false) { - if(loginId != null) { - deleteTokenToIdMapping(tokenValue); - } return; } - // 3. 清理token-id索引 - deleteTokenToIdMapping(tokenValue); // $$ 通知监听器,某某Token注销下线了 SaManager.getSaTokenListener().doLogout(loginType, loginId, tokenValue); @@ -942,7 +945,7 @@ public class StpLogic { } /** - * 清除指定token的 [最后操作时间] + * 清除指定 Token 的 [最后操作时间记录] * @param tokenValue 指定token */ protected void clearLastActivity(String tokenValue) { @@ -952,8 +955,6 @@ public class StpLogic { } // 删除[最后操作时间] getSaTokenDao().delete(splicingKeyLastActivityTime(tokenValue)); - // 清除标记 - SaHolder.getStorage().delete(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY); } /** From a7b31d74a2c3259e21b7a915391d2db62608c61c Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 8 Aug 2022 23:57:55 +0800 Subject: [PATCH 078/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/dev33/satoken/stp/StpLogic.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 0b422bf0..703a3845 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -377,18 +377,18 @@ public class StpLogic { return; } - // 从当前 [Storage存储器] 里删除 - SaHolder.getStorage().delete(splicingKeyJustCreatedSave()); - // 如果打开了 Cookie 模式,则把 Cookie 清除掉 if(getConfig().getIsReadCookie()){ SaHolder.getResponse().deleteCookie(getTokenName()); } + // 从当前 [Storage存储器] 里删除 Token + SaHolder.getStorage().delete(splicingKeyJustCreatedSave()); + // 清除当前上下文的 [临时有效期check标记] SaHolder.getStorage().delete(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY); - // 清除这个token的相关信息 + // 清除这个 Token 的相关信息 logoutByTokenValue(tokenValue); } From 664312972a34d7b47ef0a126fa3f45b804f974f0 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 9 Aug 2022 03:12:20 +0800 Subject: [PATCH 079/144] =?UTF-8?q?=E9=87=8D=E6=9E=84=20`StpLogic#getToken?= =?UTF-8?q?Session`=20=E6=96=B9=E6=B3=95=EF=BC=8C=E6=8B=92=E7=BB=9D?= =?UTF-8?q?=E4=B8=BA=E5=8C=BF=E5=90=8D=20Token=20=E5=88=9B=E5=BB=BA=20Toke?= =?UTF-8?q?n-Session=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/dev33/satoken/stp/StpLogic.java | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 703a3845..bfa08f8b 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import cn.dev33.satoken.SaManager; import cn.dev33.satoken.annotation.SaCheckLogin; @@ -101,7 +100,7 @@ public class StpLogic { * @param tokenValue token值 */ public void setTokenValue(String tokenValue){ - setTokenValue(tokenValue, (int)SaManager.getConfig().getTimeout()); + setTokenValue(tokenValue, getConfigOfCookieTimeout()); } /** @@ -896,21 +895,41 @@ public class StpLogic { // 如果配置了需要校验登录状态,则验证一下 if(getConfig().getTokenSessionCheckLogin()) { checkLogin(); + return getTokenSessionByToken(getTokenValue(), isCreate); } else { - // 如果配置忽略token登录校验,则必须保证token不为null (token为null的时候随机创建一个) + /* + * 情况1、如果调用方提供了有效 Token,则:直接返回其 [Token-Session] + * 情况2、如果调用方提供了无效 Token,或根本没有提供 Token,则:创建新 Token -> 返回 [Token-Session] + */ String tokenValue = getTokenValue(); - if(tokenValue == null || Objects.equals(tokenValue, "")) { - // 随机一个token送给Ta + + // q1 + if(SaFoxUtil.isNotEmpty(tokenValue)) { + SaSession session = getTokenSessionByToken(tokenValue, false); + if(session != null) { + return session; + } + } + + // q2 —— 此时q2又分两种情况: + /* + * 情况 2.1、isCreate=true:说明调用方想让框架帮其创建一个 SaSession,那框架就创建并返回 + * 情况 2.2、isCreate=false:说明调用方并不想让框架帮其创建一个 SaSession,那框架就直接返回 null + */ + if(isCreate) { + // 随机创建一个 Token tokenValue = createTokenValue(null, null, getConfig().getTimeout(), null); - // 写入 [最后操作时间] + // 写入 [最后操作时间] setLastActivityToNow(tokenValue); - // 在当前会话写入这个tokenValue - int cookieTimeout = (int)(getConfig().getTimeout() == SaTokenDao.NEVER_EXPIRE ? Integer.MAX_VALUE : getConfig().getTimeout()); - setTokenValue(tokenValue, cookieTimeout); + // 在当前上下文写入此 TokenValue + setTokenValue(tokenValue); + // 返回其 Token-Session 对象 + return getTokenSessionByToken(tokenValue, isCreate); + } + else { + return null; } } - // 返回这个token对应的Token-Session - return getSessionBySessionId(splicingKeyTokenSession(getTokenValue()), isCreate); } /** @@ -1815,7 +1834,20 @@ public class StpLogic { public boolean isOpenActivityCheck() { return getConfig().getActivityTimeout() != SaTokenDao.NEVER_EXPIRE; } - + + /** + * 返回全局配置的 Cookie 保存时长,单位:秒 (根据全局 timeout 计算) + * @return Cookie 应该保存的时长 + */ + public int getConfigOfCookieTimeout() { + long timeout = getConfig().getTimeout(); + if(timeout == SaTokenDao.NEVER_EXPIRE) { + return Integer.MAX_VALUE; + } + return (int) timeout; + } + + /** * 返回持久化对象 * @return / From 08ba8a0b520c8cf2fca0ed96343bf6e707c3b2a3 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 10 Aug 2022 06:50:43 +0800 Subject: [PATCH 080/144] =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E6=9F=A5=E8=AF=A2API?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=8D=E5=BA=8F=E8=8E=B7=E5=8F=96=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/dev33/satoken/dao/SaTokenDao.java | 4 +- .../satoken/dao/SaTokenDaoDefaultImpl.java | 4 +- .../java/cn/dev33/satoken/stp/StpLogic.java | 18 +++-- .../java/cn/dev33/satoken/stp/StpUtil.java | 63 +++++++++++++-- .../java/cn/dev33/satoken/util/SaFoxUtil.java | 16 +++- .../main/java/com/pj/test/TestController.java | 2 +- .../java/com/pj/satoken/at/StpUserUtil.java | 77 +++++++++++++++++-- .../main/java/com/pj/test/TestController.java | 2 +- .../java/com/pj/satoken/at/StpUserUtil.java | 77 +++++++++++++++++-- .../main/java/com/pj/test/TestController.java | 2 +- .../satoken/dao/SaTokenDaoRedisJackson.java | 4 +- .../satoken/dao/SaTokenDaoRedisString.java | 4 +- .../cn/dev33/satoken/dao/SaTokenDaoRedis.java | 4 +- .../dev33/satoken/dao/SaTokenDaoOfRedis.java | 4 +- .../satoken/jwt/StpLogicJwtForMixin.java | 2 +- .../dev33/satoken/jboot/SaTokenCacheDao.java | 4 +- .../dev33/satoken/jfinal/SaTokenDaoRedis.java | 4 +- .../cn/dev33/satoken/util/SaFoxUtilTest.java | 8 +- .../java/com/pj/test/JwtForMixinTest.java | 2 +- .../src/test/java/com/pj/test/BasicsTest.java | 2 +- 20 files changed, 246 insertions(+), 57 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java index 733d26bf..09545e58 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java @@ -170,9 +170,11 @@ public interface SaTokenDao { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return 查询到的数据集合 */ - public List searchData(String prefix, String keyword, int start, int size); + public List searchData(String prefix, String keyword, int start, int size, boolean sortType); } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java index c81c10c0..cc45b39f 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java @@ -240,8 +240,8 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao { // --------------------- 会话管理 @Override - public List searchData(String prefix, String keyword, int start, int size) { - return SaFoxUtil.searchList(expireMap.keySet(), prefix, keyword, start, size); + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { + return SaFoxUtil.searchList(expireMap.keySet(), prefix, keyword, start, size, sortType); } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index bfa08f8b..083d6330 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -1499,10 +1499,12 @@ public class StpLogic { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return token集合 */ - public List searchTokenValue(String keyword, int start, int size) { - return getSaTokenDao().searchData(splicingKeyTokenValue(""), keyword, start, size); + public List searchTokenValue(String keyword, int start, int size, boolean sortType) { + return getSaTokenDao().searchData(splicingKeyTokenValue(""), keyword, start, size, sortType); } /** @@ -1510,10 +1512,12 @@ public class StpLogic { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return sessionId集合 */ - public List searchSessionId(String keyword, int start, int size) { - return getSaTokenDao().searchData(splicingKeySession(""), keyword, start, size); + public List searchSessionId(String keyword, int start, int size, boolean sortType) { + return getSaTokenDao().searchData(splicingKeySession(""), keyword, start, size, sortType); } /** @@ -1521,10 +1525,12 @@ public class StpLogic { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return sessionId集合 */ - public List searchTokenSessionId(String keyword, int start, int size) { - return getSaTokenDao().searchData(splicingKeyTokenSession(""), keyword, start, size); + public List searchTokenSessionId(String keyword, int start, int size, boolean sortType) { + return getSaTokenDao().searchData(splicingKeyTokenSession(""), keyword, start, size, sortType); } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index 3e24922f..b631c6a4 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -692,10 +692,12 @@ public class StpUtil { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return token集合 */ - public static List searchTokenValue(String keyword, int start, int size) { - return stpLogic.searchTokenValue(keyword, start, size); + public static List searchTokenValue(String keyword, int start, int size, boolean sortType) { + return stpLogic.searchTokenValue(keyword, start, size, sortType); } /** @@ -703,10 +705,12 @@ public class StpUtil { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return sessionId集合 */ - public static List searchSessionId(String keyword, int start, int size) { - return stpLogic.searchSessionId(keyword, start, size); + public static List searchSessionId(String keyword, int start, int size, boolean sortType) { + return stpLogic.searchSessionId(keyword, start, size, sortType); } /** @@ -714,10 +718,12 @@ public class StpUtil { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return sessionId集合 */ - public static List searchTokenSessionId(String keyword, int start, int size) { - return stpLogic.searchTokenSessionId(keyword, start, size); + public static List searchTokenSessionId(String keyword, int start, int size, boolean sortType) { + return stpLogic.searchTokenSessionId(keyword, start, size, sortType); } @@ -920,5 +926,50 @@ public class StpUtil { public static void logoutByLoginId(Object loginId, String device) { stpLogic.kickout(loginId, device); } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.searchTokenValue(keyword, start, size, sortType) ,使用方式保持不变

+ * + * 根据条件查询Token + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * + * @return token集合 + */ + @Deprecated + public static List searchTokenValue(String keyword, int start, int size) { + return stpLogic.searchTokenValue(keyword, start, size, true); + } + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.searchSessionId(keyword, start, size, sortType) ,使用方式保持不变

+ * + * 根据条件查询SessionId + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * + * @return sessionId集合 + */ + @Deprecated + public static List searchSessionId(String keyword, int start, int size) { + return stpLogic.searchSessionId(keyword, start, size, true); + } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.searchTokenSessionId(keyword, start, size, sortType) ,使用方式保持不变

+ * + * 根据条件查询Token专属Session的Id + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * + * @return sessionId集合 + */ + @Deprecated + public static List searchTokenSessionId(String keyword, int start, int size) { + return stpLogic.searchTokenSessionId(keyword, start, size, true); + } + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java index cf259aaa..d0fcdb74 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java @@ -6,6 +6,7 @@ import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -111,10 +112,11 @@ public class SaFoxUtil { * @param keyword 关键字 * @param start 起始位置 (-1代表查询所有) * @param size 获取条数 + * @param sortType 排序类型(true=正序,false=反序) + * * @return 符合条件的新数据集合 */ - public static List searchList(Collection dataList, String prefix, String keyword, int start, - int size) { + public static List searchList(Collection dataList, String prefix, String keyword, int start, int size, boolean sortType) { if (prefix == null) { prefix = ""; } @@ -131,7 +133,7 @@ public class SaFoxUtil { } } // 取指定段数据 - return searchList(list, start, size); + return searchList(list, start, size, sortType); } /** @@ -140,9 +142,15 @@ public class SaFoxUtil { * @param list 数据集合 * @param start 起始位置 (-1代表查询所有) * @param size 获取条数 + * @param sortType 排序类型(true=正序,false=反序) + * * @return 符合条件的新数据集合 */ - public static List searchList(List list, int start, int size) { + public static List searchList(List list, int start, int size, boolean sortType) { + // 如果是反序的话 + if(sortType == false) { + Collections.reverse(list); + } // 取指定段数据 if (start < 0) { return list; diff --git a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/test/TestController.java b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/test/TestController.java index 64447907..8c9b4726 100644 --- a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/test/TestController.java @@ -217,7 +217,7 @@ public class TestController { public AjaxJson search() { System.out.println("--------------"); Ttime t = new Ttime().start(); - List tokenValue = StpUtil.searchTokenValue("8feb8265f773", 0, 10); + List tokenValue = StpUtil.searchTokenValue("8feb8265f773", 0, 10, true); for (String v : tokenValue) { // SaSession session = StpUtil.getSessionBySessionId(sid); System.out.println(v); diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java index eeb3945c..db173bd3 100644 --- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java +++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java @@ -10,7 +10,7 @@ import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpLogic; /** - * Sa-Token 权限认证工具类 (user版) + * Sa-Token 权限认证工具类 (User版) * @author kong */ public class StpUserUtil { @@ -316,13 +316,23 @@ public class StpUserUtil { } /** - * 获取Token扩展信息(只在jwt模式下有效) + * 获取当前 Token 的扩展信息(此函数只在jwt模式下生效) * @param key 键值 * @return 对应的扩展数据 */ public static Object getExtra(String key) { return stpLogic.getExtra(key); } + + /** + * 获取指定 Token 的扩展信息(此函数只在jwt模式下生效) + * @param tokenValue 指定的 Token 值 + * @param key 键值 + * @return 对应的扩展数据 + */ + public static Object getExtra(String tokenValue, String key) { + return stpLogic.getExtra(tokenValue, key); + } // =================== User-Session 相关 =================== @@ -685,10 +695,12 @@ public class StpUserUtil { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return token集合 */ - public static List searchTokenValue(String keyword, int start, int size) { - return stpLogic.searchTokenValue(keyword, start, size); + public static List searchTokenValue(String keyword, int start, int size, boolean sortType) { + return stpLogic.searchTokenValue(keyword, start, size, sortType); } /** @@ -696,10 +708,12 @@ public class StpUserUtil { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return sessionId集合 */ - public static List searchSessionId(String keyword, int start, int size) { - return stpLogic.searchSessionId(keyword, start, size); + public static List searchSessionId(String keyword, int start, int size, boolean sortType) { + return stpLogic.searchSessionId(keyword, start, size, sortType); } /** @@ -707,10 +721,12 @@ public class StpUserUtil { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return sessionId集合 */ - public static List searchTokenSessionId(String keyword, int start, int size) { - return stpLogic.searchTokenSessionId(keyword, start, size); + public static List searchTokenSessionId(String keyword, int start, int size, boolean sortType) { + return stpLogic.searchTokenSessionId(keyword, start, size, sortType); } @@ -913,5 +929,50 @@ public class StpUserUtil { public static void logoutByLoginId(Object loginId, String device) { stpLogic.kickout(loginId, device); } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.searchTokenValue(keyword, start, size, sortType) ,使用方式保持不变

+ * + * 根据条件查询Token + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * + * @return token集合 + */ + @Deprecated + public static List searchTokenValue(String keyword, int start, int size) { + return stpLogic.searchTokenValue(keyword, start, size, true); + } + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.searchSessionId(keyword, start, size, sortType) ,使用方式保持不变

+ * + * 根据条件查询SessionId + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * + * @return sessionId集合 + */ + @Deprecated + public static List searchSessionId(String keyword, int start, int size) { + return stpLogic.searchSessionId(keyword, start, size, true); + } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.searchTokenSessionId(keyword, start, size, sortType) ,使用方式保持不变

+ * + * 根据条件查询Token专属Session的Id + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * + * @return sessionId集合 + */ + @Deprecated + public static List searchTokenSessionId(String keyword, int start, int size) { + return stpLogic.searchTokenSessionId(keyword, start, size, true); + } + } diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/test/TestController.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/test/TestController.java index 0712eb2d..92096114 100644 --- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/test/TestController.java @@ -218,7 +218,7 @@ public class TestController { public AjaxJson search() { System.out.println("--------------"); Ttime t = new Ttime().start(); - List tokenValue = StpUtil.searchTokenValue("8feb8265f773", 0, 10); + List tokenValue = StpUtil.searchTokenValue("8feb8265f773", 0, 10, true); for (String v : tokenValue) { // SaSession session = StpUtil.getSessionBySessionId(sid); System.out.println(v); diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java index eeb3945c..db173bd3 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java @@ -10,7 +10,7 @@ import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpLogic; /** - * Sa-Token 权限认证工具类 (user版) + * Sa-Token 权限认证工具类 (User版) * @author kong */ public class StpUserUtil { @@ -316,13 +316,23 @@ public class StpUserUtil { } /** - * 获取Token扩展信息(只在jwt模式下有效) + * 获取当前 Token 的扩展信息(此函数只在jwt模式下生效) * @param key 键值 * @return 对应的扩展数据 */ public static Object getExtra(String key) { return stpLogic.getExtra(key); } + + /** + * 获取指定 Token 的扩展信息(此函数只在jwt模式下生效) + * @param tokenValue 指定的 Token 值 + * @param key 键值 + * @return 对应的扩展数据 + */ + public static Object getExtra(String tokenValue, String key) { + return stpLogic.getExtra(tokenValue, key); + } // =================== User-Session 相关 =================== @@ -685,10 +695,12 @@ public class StpUserUtil { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return token集合 */ - public static List searchTokenValue(String keyword, int start, int size) { - return stpLogic.searchTokenValue(keyword, start, size); + public static List searchTokenValue(String keyword, int start, int size, boolean sortType) { + return stpLogic.searchTokenValue(keyword, start, size, sortType); } /** @@ -696,10 +708,12 @@ public class StpUserUtil { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return sessionId集合 */ - public static List searchSessionId(String keyword, int start, int size) { - return stpLogic.searchSessionId(keyword, start, size); + public static List searchSessionId(String keyword, int start, int size, boolean sortType) { + return stpLogic.searchSessionId(keyword, start, size, sortType); } /** @@ -707,10 +721,12 @@ public class StpUserUtil { * @param keyword 关键字 * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 + * @param sortType 排序类型(true=正序,false=反序) + * * @return sessionId集合 */ - public static List searchTokenSessionId(String keyword, int start, int size) { - return stpLogic.searchTokenSessionId(keyword, start, size); + public static List searchTokenSessionId(String keyword, int start, int size, boolean sortType) { + return stpLogic.searchTokenSessionId(keyword, start, size, sortType); } @@ -913,5 +929,50 @@ public class StpUserUtil { public static void logoutByLoginId(Object loginId, String device) { stpLogic.kickout(loginId, device); } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.searchTokenValue(keyword, start, size, sortType) ,使用方式保持不变

+ * + * 根据条件查询Token + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * + * @return token集合 + */ + @Deprecated + public static List searchTokenValue(String keyword, int start, int size) { + return stpLogic.searchTokenValue(keyword, start, size, true); + } + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.searchSessionId(keyword, start, size, sortType) ,使用方式保持不变

+ * + * 根据条件查询SessionId + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * + * @return sessionId集合 + */ + @Deprecated + public static List searchSessionId(String keyword, int start, int size) { + return stpLogic.searchSessionId(keyword, start, size, true); + } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.searchTokenSessionId(keyword, start, size, sortType) ,使用方式保持不变

+ * + * 根据条件查询Token专属Session的Id + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * + * @return sessionId集合 + */ + @Deprecated + public static List searchTokenSessionId(String keyword, int start, int size) { + return stpLogic.searchTokenSessionId(keyword, start, size, true); + } + } diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java index 0712eb2d..92096114 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java @@ -218,7 +218,7 @@ public class TestController { public AjaxJson search() { System.out.println("--------------"); Ttime t = new Ttime().start(); - List tokenValue = StpUtil.searchTokenValue("8feb8265f773", 0, 10); + List tokenValue = StpUtil.searchTokenValue("8feb8265f773", 0, 10, true); for (String v : tokenValue) { // SaSession session = StpUtil.getSessionBySessionId(sid); System.out.println(v); diff --git a/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java b/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java index c3442149..98c3a2a4 100644 --- a/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java +++ b/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java @@ -271,10 +271,10 @@ public class SaTokenDaoRedisJackson implements SaTokenDao { * 搜索数据 */ @Override - public List searchData(String prefix, String keyword, int start, int size) { + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { Set keys = stringRedisTemplate.keys(prefix + "*" + keyword + "*"); List list = new ArrayList(keys); - return SaFoxUtil.searchList(list, start, size); + return SaFoxUtil.searchList(list, start, size, sortType); } } diff --git a/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java b/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java index 2f849e93..9a588605 100644 --- a/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java +++ b/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java @@ -226,10 +226,10 @@ public class SaTokenDaoRedisString implements SaTokenDao { * 搜索数据 */ @Override - public List searchData(String prefix, String keyword, int start, int size) { + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { Set keys = stringRedisTemplate.keys(prefix + "*" + keyword + "*"); List list = new ArrayList(keys); - return SaFoxUtil.searchList(list, start, size); + return SaFoxUtil.searchList(list, start, size, sortType); } diff --git a/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java b/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java index 532f844d..a4bf7870 100644 --- a/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java +++ b/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java @@ -217,10 +217,10 @@ public class SaTokenDaoRedis implements SaTokenDao { * 搜索数据 */ @Override - public List searchData(String prefix, String keyword, int start, int size) { + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { Set keys = stringRedisTemplate.keys(prefix + "*" + keyword + "*"); List list = new ArrayList(keys); - return SaFoxUtil.searchList(list, start, size); + return SaFoxUtil.searchList(list, start, size, sortType); } diff --git a/sa-token-plugin/sa-token-dao-redisx/src/main/java/cn/dev33/satoken/dao/SaTokenDaoOfRedis.java b/sa-token-plugin/sa-token-dao-redisx/src/main/java/cn/dev33/satoken/dao/SaTokenDaoOfRedis.java index 34572a56..d499570a 100644 --- a/sa-token-plugin/sa-token-dao-redisx/src/main/java/cn/dev33/satoken/dao/SaTokenDaoOfRedis.java +++ b/sa-token-plugin/sa-token-dao-redisx/src/main/java/cn/dev33/satoken/dao/SaTokenDaoOfRedis.java @@ -177,9 +177,9 @@ public class SaTokenDaoOfRedis implements SaTokenDao { * 搜索数据 */ @Override - public List searchData(String prefix, String keyword, int start, int size) { + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { Set keys = redisBucket.keys(prefix + "*" + keyword + "*"); List list = new ArrayList(keys); - return SaFoxUtil.searchList(list, start, size); + return SaFoxUtil.searchList(list, start, size, sortType); } } \ No newline at end of file diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java index 8aa555bb..d839e3aa 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java @@ -204,7 +204,7 @@ public class StpLogicJwtForMixin extends StpLogic { * [禁用] 根据条件查询Token */ @Override - public List searchTokenValue(String keyword, int start, int size) { + public List searchTokenValue(String keyword, int start, int size, boolean sortType) { throw new ApiDisabledException(); } diff --git a/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenCacheDao.java b/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenCacheDao.java index a95e6a25..65ff67c2 100644 --- a/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenCacheDao.java +++ b/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenCacheDao.java @@ -252,12 +252,12 @@ public class SaTokenCacheDao implements SaTokenDao { } @Override - public List searchData(String prefix, String keyword, int start, int size) { + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { Jedis jedis = saRedisCache.getJedis(); try { Set keys = jedis.keys(prefix + "*" + keyword + "*"); List list = new ArrayList(keys); - return SaFoxUtil.searchList(list, start, size); + return SaFoxUtil.searchList(list, start, size, sortType); } finally { saRedisCache.returnResource(jedis); } diff --git a/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenDaoRedis.java b/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenDaoRedis.java index 6ea97aff..99552212 100644 --- a/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenDaoRedis.java +++ b/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenDaoRedis.java @@ -257,10 +257,10 @@ public class SaTokenDaoRedis implements SaTokenDao { * @return */ @Override - public List searchData(String prefix, String keyword, int start, int size) { + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { Set keys = redis.keys(prefix + "*" + keyword + "*"); List list = new ArrayList(keys); - return SaFoxUtil.searchList(list, start, size); + return SaFoxUtil.searchList(list, start, size, sortType); } public Jedis getJedis() { diff --git a/sa-token-test/sa-token-core-test/src/test/java/cn/dev33/satoken/util/SaFoxUtilTest.java b/sa-token-test/sa-token-core-test/src/test/java/cn/dev33/satoken/util/SaFoxUtilTest.java index d7cca62c..8863da95 100644 --- a/sa-token-test/sa-token-core-test/src/test/java/cn/dev33/satoken/util/SaFoxUtilTest.java +++ b/sa-token-test/sa-token-core-test/src/test/java/cn/dev33/satoken/util/SaFoxUtilTest.java @@ -47,21 +47,21 @@ public class SaFoxUtilTest { List dataList = Arrays.asList("token1", "token2", "token3", "token4", "token5", "aaa1"); // 分页 - List list1 = SaFoxUtil.searchList(dataList, 1, 2); + List list1 = SaFoxUtil.searchList(dataList, 1, 2, true); Assertions.assertEquals(list1.size(), 2); Assertions.assertEquals(list1.get(0), "token2"); Assertions.assertEquals(list1.get(1), "token3"); // 前缀筛选 - List list2 = SaFoxUtil.searchList(dataList, "token", "", 0, 10); + List list2 = SaFoxUtil.searchList(dataList, "token", "", 0, 10, true); Assertions.assertEquals(list2.size(), 5); // 关键字筛选 - List list3 = SaFoxUtil.searchList(dataList, "", "1", 0, 10); + List list3 = SaFoxUtil.searchList(dataList, "", "1", 0, 10, true); Assertions.assertEquals(list3.size(), 2); // 综合筛选 - List list4 = SaFoxUtil.searchList(dataList, "token", "1", 0, 10); + List list4 = SaFoxUtil.searchList(dataList, "token", "1", 0, 10, true); Assertions.assertEquals(list4.size(), 1); } diff --git a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java index ef6ed9e2..50701740 100644 --- a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java +++ b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java @@ -251,7 +251,7 @@ public class JwtForMixinTest { StpUtil.login(10005); // 查询 - List list = StpUtil.searchTokenValue("", 0, 10); + List list = StpUtil.searchTokenValue("", 0, 10, true); Assertions.assertTrue(list.size() >= 5); }); } diff --git a/sa-token-test/sa-token-springboot-test/src/test/java/com/pj/test/BasicsTest.java b/sa-token-test/sa-token-springboot-test/src/test/java/com/pj/test/BasicsTest.java index a0dada01..a744ec8c 100644 --- a/sa-token-test/sa-token-springboot-test/src/test/java/com/pj/test/BasicsTest.java +++ b/sa-token-test/sa-token-springboot-test/src/test/java/com/pj/test/BasicsTest.java @@ -316,7 +316,7 @@ public class BasicsTest { StpUtil.login(10005); // 查询 - List list = StpUtil.searchTokenValue("", 0, 10); + List list = StpUtil.searchTokenValue("", 0, 10, true); Assertions.assertTrue(list.size() >= 5); } From 055f2c9aa2e79660bee9a2308ba3decca890aef7 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 11 Aug 2022 01:52:28 +0800 Subject: [PATCH 081/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/up/search-session.md | 9 +++++---- sa-token-doc/doc/use/config.md | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/sa-token-doc/doc/up/search-session.md b/sa-token-doc/doc/up/search-session.md index aaa661eb..3e6d6c31 100644 --- a/sa-token-doc/doc/up/search-session.md +++ b/sa-token-doc/doc/up/search-session.md @@ -11,13 +11,13 @@ Sa-Token提供以下API助你直接操作会话列表: ``` java // 查询所有token -StpUtil.searchTokenValue(String keyword, int start, int size); +StpUtil.searchTokenValue(String keyword, int start, int size, boolean sortType); // 查询所有账号Session会话 -StpUtil.searchSessionId(String keyword, int start, int size); +StpUtil.searchSessionId(String keyword, int start, int size, boolean sortType); // 查询所有令牌Session会话 -StpUtil.searchTokenSessionId(String keyword, int start, int size); +StpUtil.searchTokenSessionId(String keyword, int start, int size, boolean sortType); ``` @@ -25,11 +25,12 @@ StpUtil.searchTokenSessionId(String keyword, int start, int size); - `keyword`: 查询关键字,只有包括这个字符串的 token 值才会被查询出来。 - `start`: 数据开始处索引, 值为-1时代表一次性取出所有数据。 - `size`: 要获取的数据条数。 +- `sortType`: 排序方式(true=正序,false=反序)。 使用示例: ``` java // 查询value包括1000的所有token,结果集从第0条开始,返回10条 -List tokenList = StpUtil.searchTokenValue("1000", 0, 10); +List tokenList = StpUtil.searchTokenValue("1000", 0, 10, true); for (String token : tokenList) { System.out.println(token); } diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index 89410b71..71896b8e 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -233,7 +233,10 @@ sa-token: 这样就保证了伪造的 Token 是无法获取 `Token-Session` 对象的。 -但是 —— 有的场景下我们又确实需要关闭这个校验功能,这时候就把配置项 `tokenSessionCheckLogin` 值改为 `false` 即可。 +但是 —— 有的场景下我们又确实需要在登录之前就使用 Token-Session 对象,这时候就把配置项 `tokenSessionCheckLogin` 值改为 `false` 即可。 + +需要注意的一点是:此时如果前端提交的 Token 是一个无效 Token 的话,框架将不会根据此 Token 创建 `Token-Session` 对象, +而是随机一个新的 Token 值来创建 `Token-Session` 对象,此 Token 值可以通过 `StpUtil.getTokenValue()` 获取到。 #### isAutoMode From 32e1b49fe946ba11fc5948a003883a358035b473 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 13 Aug 2022 02:53:52 +0800 Subject: [PATCH 082/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20`StpLogic#getAnonT?= =?UTF-8?q?okenSession`=20=E6=96=B9=E6=B3=95=EF=BC=8C=E5=8F=AF=E5=9C=A8?= =?UTF-8?q?=E6=9C=AA=E7=99=BB=E5=BD=95=E6=83=85=E5=86=B5=E4=B8=8B=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E7=9A=84=E8=8E=B7=E5=8F=96=20Token-Session?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/dev33/satoken/stp/StpLogic.java | 106 ++++++++++++------ .../java/cn/dev33/satoken/stp/StpUtil.java | 8 ++ 2 files changed, 79 insertions(+), 35 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 083d6330..d30bcfb1 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -892,44 +892,17 @@ public class StpLogic { * @return Session对象 */ public SaSession getTokenSession(boolean isCreate) { + // Token 为空的情况下直接返回 null + String tokenValue = getTokenValue(); + if(SaFoxUtil.isEmpty(tokenValue)) { + return null; + } // 如果配置了需要校验登录状态,则验证一下 if(getConfig().getTokenSessionCheckLogin()) { checkLogin(); - return getTokenSessionByToken(getTokenValue(), isCreate); - } else { - /* - * 情况1、如果调用方提供了有效 Token,则:直接返回其 [Token-Session] - * 情况2、如果调用方提供了无效 Token,或根本没有提供 Token,则:创建新 Token -> 返回 [Token-Session] - */ - String tokenValue = getTokenValue(); - - // q1 - if(SaFoxUtil.isNotEmpty(tokenValue)) { - SaSession session = getTokenSessionByToken(tokenValue, false); - if(session != null) { - return session; - } - } - - // q2 —— 此时q2又分两种情况: - /* - * 情况 2.1、isCreate=true:说明调用方想让框架帮其创建一个 SaSession,那框架就创建并返回 - * 情况 2.2、isCreate=false:说明调用方并不想让框架帮其创建一个 SaSession,那框架就直接返回 null - */ - if(isCreate) { - // 随机创建一个 Token - tokenValue = createTokenValue(null, null, getConfig().getTimeout(), null); - // 写入 [最后操作时间] - setLastActivityToNow(tokenValue); - // 在当前上下文写入此 TokenValue - setTokenValue(tokenValue); - // 返回其 Token-Session 对象 - return getTokenSessionByToken(tokenValue, isCreate); - } - else { - return null; - } - } + } + // 获取 SaSession 数据 + return getTokenSessionByToken(tokenValue, isCreate); } /** @@ -939,6 +912,64 @@ public class StpLogic { public SaSession getTokenSession() { return getTokenSession(true); } + + /** + * 获取当前匿名 Token-Session (可在未登录情况下使用的Token-Session) + * @param isCreate 在 Token-Session 尚未创建的情况是否新建并返回 + * @return Token-Session 对象 + */ + public SaSession getAnonTokenSession(boolean isCreate) { + /* + * 情况1、如果调用方提供了有效 Token,则:直接返回其 [Token-Session] + * 情况2、如果调用方提供了无效 Token,或根本没有提供 Token,则:创建新 Token -> 返回 [Token-Session] + */ + String tokenValue = getTokenValue(); + + // q1 —— 判断这个 Token 是否有效,两个条件符合其一即可: + /* + * 条件1、能查出 Token-Session + * 条件2、能查出 LoginId + */ + if(SaFoxUtil.isNotEmpty(tokenValue)) { + // 符合条件1 + SaSession session = getTokenSessionByToken(tokenValue, false); + if(session != null) { + return session; + } + // 符合条件2 + String loginId = getLoginIdNotHandle(tokenValue); + if(isValidLoginId(loginId)) { + return getTokenSessionByToken(tokenValue, isCreate); + } + } + + // q2 —— 此时q2分两种情况: + /* + * 情况 2.1、isCreate=true:说明调用方想让框架帮其创建一个 SaSession,那框架就创建并返回 + * 情况 2.2、isCreate=false:说明调用方并不想让框架帮其创建一个 SaSession,那框架就直接返回 null + */ + if(isCreate) { + // 随机创建一个 Token + tokenValue = createTokenValue(null, null, getConfig().getTimeout(), null); + // 写入 [最后操作时间] + setLastActivityToNow(tokenValue); + // 在当前上下文写入此 TokenValue + setTokenValue(tokenValue); + // 返回其 Token-Session 对象 + return getTokenSessionByToken(tokenValue, isCreate); + } + else { + return null; + } + } + + /** + * 获取当前匿名 Token-Session (可在未登录情况下使用的Token-Session) + * @return Token-Session 对象 + */ + public SaSession getAnonTokenSession() { + return getAnonTokenSession(true); + } /** * 删除Token-Session @@ -1602,6 +1633,11 @@ public class StpLogic { * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) */ public void disable(Object loginId, long disableTime) { + // 空值不做处理 + if(SaFoxUtil.isEmpty(loginId)) { + return; + } + // 标注为已被封禁 getSaTokenDao().set(splicingKeyDisable(loginId), DisableLoginException.BE_VALUE, disableTime); diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index b631c6a4..7343c335 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -399,6 +399,14 @@ public class StpUtil { return stpLogic.getTokenSession(); } + /** + * 获取当前匿名 Token-Session (可在未登录情况下使用的Token-Session) + * @return Token-Session 对象 + */ + public static SaSession getAnonTokenSession() { + return stpLogic.getAnonTokenSession(); + } + // =================== [临时有效期] 验证相关 =================== From b232abbb091dad4c95ee66c203b91b2637c9c686 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 13 Aug 2022 03:13:54 +0800 Subject: [PATCH 083/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/use/config.md | 3 --- sa-token-doc/doc/use/session.md | 9 ++++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index 71896b8e..b39028e6 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -235,9 +235,6 @@ sa-token: 但是 —— 有的场景下我们又确实需要在登录之前就使用 Token-Session 对象,这时候就把配置项 `tokenSessionCheckLogin` 值改为 `false` 即可。 -需要注意的一点是:此时如果前端提交的 Token 是一个无效 Token 的话,框架将不会根据此 Token 创建 `Token-Session` 对象, -而是随机一个新的 Token 值来创建 `Token-Session` 对象,此 Token 值可以通过 `StpUtil.getTokenValue()` 获取到。 - #### isAutoMode diff --git a/sa-token-doc/doc/use/session.md b/sa-token-doc/doc/use/session.md index f5af77fb..97c6dce5 100644 --- a/sa-token-doc/doc/use/session.md +++ b/sa-token-doc/doc/use/session.md @@ -45,13 +45,16 @@ StpUtil.getSessionBySessionId("xxxx-xxxx"); ### Token-Session 有关令牌Session的API如下: ``` java -// 获取当前token的专属Session +// 获取当前 Token 的 Token-Session 对象 StpUtil.getTokenSession(); -// 获取指定token的专属Session +// 获取指定 Token 的 Token-Session 对象 StpUtil.getTokenSessionByToken(token); + +// 获取当前 Token 的匿名 Token-Session (可在未登录情况下使用的Token-Session) +StpUtil.getAnonTokenSession(); ``` -在未登录状态下是否可以获取`Token-Session`?这取决于你配置的`tokenSessionCheckLogin`值是否为false,详见:[框架配置](/use/config?id=所有可配置项) +在未登录状态下是否通过 `StpUtil.getTokenSession()` 获取`Token-Session`?这取决于你配置的`tokenSessionCheckLogin`值是否为false,详见:[框架配置](/use/config?id=所有可配置项) ### 自定义Session From d07118fc0c61e7719584fb154537a8e2c15b6d06 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 13 Aug 2022 03:19:48 +0800 Subject: [PATCH 084/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=8C=BF=E5=90=8D=20?= =?UTF-8?q?Token-Session=20=E7=9A=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/use/session.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/sa-token-doc/doc/use/session.md b/sa-token-doc/doc/use/session.md index 97c6dce5..6ace86c7 100644 --- a/sa-token-doc/doc/use/session.md +++ b/sa-token-doc/doc/use/session.md @@ -50,11 +50,7 @@ StpUtil.getTokenSession(); // 获取指定 Token 的 Token-Session 对象 StpUtil.getTokenSessionByToken(token); - -// 获取当前 Token 的匿名 Token-Session (可在未登录情况下使用的Token-Session) -StpUtil.getAnonTokenSession(); ``` -在未登录状态下是否通过 `StpUtil.getTokenSession()` 获取`Token-Session`?这取决于你配置的`tokenSessionCheckLogin`值是否为false,详见:[框架配置](/use/config?id=所有可配置项) ### 自定义Session @@ -148,3 +144,20 @@ public void reset(HttpSession session) { 1. `SaSession` 与 `HttpSession` 没有任何关系,在`HttpSession`上写入的值,在`SaSession`中无法取出 2. `HttpSession`并未被框架接管,在使用Sa-Token时,请在任何情况下均使用`SaSession`,不要使用`HttpSession` + +### 未登录场景下获取 Token-Session + +默认场景下,只有登录后才能通过 `StpUtil.getTokenSession()` 获取 `Token-Session`。 + +如果想要在未登录场景下获取 Token-Session ,有两种方法: + +- 方法一:将全局配置项 `tokenSessionCheckLogin` 改为 false,详见:[框架配置](/use/config?id=所有可配置项) +- 方法二:使用匿名 Token-Session + +``` java +// 获取当前 Token 的匿名 Token-Session (可在未登录情况下使用的 Token-Session) +StpUtil.getAnonTokenSession(); +``` + +注意点:如果前端没有提交 Token ,或者提交的 Token 是一个无效 Token 的话,框架将不会根据此 Token 创建 `Token-Session` 对象, +而是随机一个新的 Token 值来创建 `Token-Session` 对象,此 Token 值可以通过 `StpUtil.getTokenValue()` 获取到。 From 390d7140a2e5d19cc39de440955152b2822a4e11 Mon Sep 17 00:00:00 2001 From: "andy.l.an" <826737577@qq.com> Date: Fri, 12 Aug 2022 10:52:36 +0800 Subject: [PATCH 085/144] =?UTF-8?q?#I5KWJ8=20=E7=99=BB=E9=99=86=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=A2=9E=E5=8A=A0=E6=8C=87=E5=AE=9A=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E8=BF=87=E6=9C=9F=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/dev33/satoken/stp/StpLogic.java | 124 ++++++++++-------- .../java/cn/dev33/satoken/stp/StpUtil.java | 28 ++-- 2 files changed, 87 insertions(+), 65 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index d30bcfb1..4bcf9354 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -1,10 +1,5 @@ package cn.dev33.satoken.stp; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - import cn.dev33.satoken.SaManager; import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckPermission; @@ -32,6 +27,11 @@ import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaTokenConsts; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + /** * Sa-Token 权限认证,逻辑实现类 * @author kong @@ -270,6 +270,16 @@ public class StpLogic { login(id, new SaLoginModel().setIsLastingCookie(isLastingCookie)); } + /** + * 会话登录,并指定此次登录token的有效期, 单位:秒 + * + * @param id 账号id,建议的类型:(long | int | String) + * @param timeout 此次登录token的有效期, 单位:秒 + */ + public void login(Object id, long timeout) { + login(id, new SaLoginModel().setTimeout(timeout)); + } + /** * 会话登录,并指定所有登录参数Model * @param id 登录id,建议的类型:(long | int | String) @@ -318,7 +328,7 @@ public class StpLogic { // 如果配置为共享token, 则尝试从Session签名记录里取出token if(getConfigOfIsShare()) { // 为确保 jwt-simple 模式的 token Extra 数据生成不受旧token影响,这里必须确保 is-share 配置项在 ExtraData 为空时才可以生效 - // 即:在 login 时提供了 Extra 数据后,即使配置了 is-share=true 也不能复用旧 Token,必须创建新 Token + // 即:在 login 时提供了 Extra 数据后,即使配置了 is-share=true 也不能复用旧 Token,必须创建新 Token if(loginModel.getExtraData() == null || loginModel.getExtraData().size() == 0) { tokenValue = getTokenValueByLoginId(id, loginModel.getDeviceOrDefault()); } @@ -370,24 +380,24 @@ public class StpLogic { * 会话注销 */ public void logout() { - // 如果连 Token 都没有,那么无需执行任何操作 + // 如果连 Token 都没有,那么无需执行任何操作 String tokenValue = getTokenValue(); if(SaFoxUtil.isEmpty(tokenValue)) { return; } - // 如果打开了 Cookie 模式,则把 Cookie 清除掉 + // 如果打开了 Cookie 模式,则把 Cookie 清除掉 if(getConfig().getIsReadCookie()){ SaHolder.getResponse().deleteCookie(getTokenName()); } - // 从当前 [Storage存储器] 里删除 Token + // 从当前 [Storage存储器] 里删除 Token SaHolder.getStorage().delete(splicingKeyJustCreatedSave()); - - // 清除当前上下文的 [临时有效期check标记] + + // 清除当前上下文的 [临时有效期check标记] SaHolder.getStorage().delete(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY); - - // 清除这个 Token 的相关信息 + + // 清除这个 Token 的相关信息 logoutByTokenValue(tokenValue); } @@ -471,13 +481,13 @@ public class StpLogic { // 2. 注销 Token-Session deleteTokenSession(tokenValue); - // 3. 清理 token -> id 索引 + // 3. 清理 token -> id 索引 String loginId = getLoginIdNotHandle(tokenValue); if(loginId != null) { deleteTokenToIdMapping(tokenValue); } - // if. 无效 loginId 立即返回 + // if. 无效 loginId 立即返回 if(isValidLoginId(loginId) == false) { return; } @@ -756,14 +766,14 @@ public class StpLogic { /** * 获取指定 Token 的扩展信息(此函数只在jwt模式下生效) - * @param tokenValue 指定的 Token 值 - * @param key 键值 - * @return 对应的扩展数据 + * @param tokenValue 指定的 Token 值 + * @param key 键值 + * @return 对应的扩展数据 */ public Object getExtra(String tokenValue, String key) { throw new ApiDisabledException(); } - + // ---- 其它操作 /** @@ -892,7 +902,7 @@ public class StpLogic { * @return Session对象 */ public SaSession getTokenSession(boolean isCreate) { - // Token 为空的情况下直接返回 null + // Token 为空的情况下直接返回 null String tokenValue = getTokenValue(); if(SaFoxUtil.isEmpty(tokenValue)) { return null; @@ -900,35 +910,35 @@ public class StpLogic { // 如果配置了需要校验登录状态,则验证一下 if(getConfig().getTokenSessionCheckLogin()) { checkLogin(); - } - // 获取 SaSession 数据 + } + // 获取 SaSession 数据 return getTokenSessionByToken(tokenValue, isCreate); } - - /** + + /** * 获取当前Token-Session,如果Session尚未创建,则新建并返回 - * @return Session对象 + * @return Session对象 */ public SaSession getTokenSession() { return getTokenSession(true); } - /** + /** * 获取当前匿名 Token-Session (可在未登录情况下使用的Token-Session) - * @param isCreate 在 Token-Session 尚未创建的情况是否新建并返回 - * @return Token-Session 对象 + * @param isCreate 在 Token-Session 尚未创建的情况是否新建并返回 + * @return Token-Session 对象 */ public SaSession getAnonTokenSession(boolean isCreate) { - /* + /* * 情况1、如果调用方提供了有效 Token,则:直接返回其 [Token-Session] - * 情况2、如果调用方提供了无效 Token,或根本没有提供 Token,则:创建新 Token -> 返回 [Token-Session] + * 情况2、如果调用方提供了无效 Token,或根本没有提供 Token,则:创建新 Token -> 返回 [Token-Session] */ String tokenValue = getTokenValue(); - + // q1 —— 判断这个 Token 是否有效,两个条件符合其一即可: /* - * 条件1、能查出 Token-Session - * 条件2、能查出 LoginId + * 条件1、能查出 Token-Session + * 条件2、能查出 LoginId */ if(SaFoxUtil.isNotEmpty(tokenValue)) { // 符合条件1 @@ -936,28 +946,28 @@ public class StpLogic { if(session != null) { return session; } - // 符合条件2 + // 符合条件2 String loginId = getLoginIdNotHandle(tokenValue); if(isValidLoginId(loginId)) { return getTokenSessionByToken(tokenValue, isCreate); } } - + // q2 —— 此时q2分两种情况: /* - * 情况 2.1、isCreate=true:说明调用方想让框架帮其创建一个 SaSession,那框架就创建并返回 - * 情况 2.2、isCreate=false:说明调用方并不想让框架帮其创建一个 SaSession,那框架就直接返回 null + * 情况 2.1、isCreate=true:说明调用方想让框架帮其创建一个 SaSession,那框架就创建并返回 + * 情况 2.2、isCreate=false:说明调用方并不想让框架帮其创建一个 SaSession,那框架就直接返回 null */ if(isCreate) { - // 随机创建一个 Token + // 随机创建一个 Token tokenValue = createTokenValue(null, null, getConfig().getTimeout(), null); - // 写入 [最后操作时间] - setLastActivityToNow(tokenValue); - // 在当前上下文写入此 TokenValue + // 写入 [最后操作时间] + setLastActivityToNow(tokenValue); + // 在当前上下文写入此 TokenValue setTokenValue(tokenValue); - // 返回其 Token-Session 对象 + // 返回其 Token-Session 对象 return getTokenSessionByToken(tokenValue, isCreate); - } + } else { return null; } @@ -965,7 +975,7 @@ public class StpLogic { /** * 获取当前匿名 Token-Session (可在未登录情况下使用的Token-Session) - * @return Token-Session 对象 + * @return Token-Session 对象 */ public SaSession getAnonTokenSession() { return getAnonTokenSession(true); @@ -995,7 +1005,7 @@ public class StpLogic { } /** - * 清除指定 Token 的 [最后操作时间记录] + * 清除指定 Token 的 [最后操作时间记录] * @param tokenValue 指定token */ protected void clearLastActivity(String tokenValue) { @@ -1531,8 +1541,8 @@ public class StpLogic { * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 * @param sortType 排序类型(true=正序,false=反序) - * - * @return token集合 + * + * @return token集合 */ public List searchTokenValue(String keyword, int start, int size, boolean sortType) { return getSaTokenDao().searchData(splicingKeyTokenValue(""), keyword, start, size, sortType); @@ -1544,8 +1554,8 @@ public class StpLogic { * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 * @param sortType 排序类型(true=正序,false=反序) - * - * @return sessionId集合 + * + * @return sessionId集合 */ public List searchSessionId(String keyword, int start, int size, boolean sortType) { return getSaTokenDao().searchData(splicingKeySession(""), keyword, start, size, sortType); @@ -1557,8 +1567,8 @@ public class StpLogic { * @param start 开始处索引 (-1代表查询所有) * @param size 获取数量 * @param sortType 排序类型(true=正序,false=反序) - * - * @return sessionId集合 + * + * @return sessionId集合 */ public List searchTokenSessionId(String keyword, int start, int size, boolean sortType) { return getSaTokenDao().searchData(splicingKeyTokenSession(""), keyword, start, size, sortType); @@ -1633,12 +1643,12 @@ public class StpLogic { * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) */ public void disable(Object loginId, long disableTime) { - // 空值不做处理 + // 空值不做处理 if(SaFoxUtil.isEmpty(loginId)) { return; } - - // 标注为已被封禁 + + // 标注为已被封禁 getSaTokenDao().set(splicingKeyDisable(loginId), DisableLoginException.BE_VALUE, disableTime); // $$ 通知监听器 @@ -1878,7 +1888,7 @@ public class StpLogic { } /** - * 返回全局配置的 Cookie 保存时长,单位:秒 (根据全局 timeout 计算) + * 返回全局配置的 Cookie 保存时长,单位:秒 (根据全局 timeout 计算) * @return Cookie 应该保存的时长 */ public int getConfigOfCookieTimeout() { @@ -1888,8 +1898,8 @@ public class StpLogic { } return (int) timeout; } - - + + /** * 返回持久化对象 * @return / diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index 7343c335..202d0f0e 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -1,11 +1,11 @@ package cn.dev33.satoken.stp; -import java.util.List; - import cn.dev33.satoken.SaManager; import cn.dev33.satoken.fun.SaFunction; import cn.dev33.satoken.session.SaSession; +import java.util.List; + /** * Sa-Token 权限认证工具类 * @author kong @@ -121,18 +121,30 @@ public class StpUtil { } /** - * 会话登录,并指定是否 [记住我] - * @param id 账号id,建议的类型:(long | int | String) - * @param isLastingCookie 是否为持久Cookie + * 会话登录,并指定是否 [记住我] + * + * @param id 账号id,建议的类型:(long | int | String) + * @param isLastingCookie 是否为持久Cookie */ public static void login(Object id, boolean isLastingCookie) { stpLogic.login(id, isLastingCookie); } /** - * 会话登录,并指定所有登录参数Model - * @param id 登录id,建议的类型:(long | int | String) - * @param loginModel 此次登录的参数Model + * 会话登录,并指定此次登录token的有效期, 单位:秒 + * + * @param id 账号id,建议的类型:(long | int | String) + * @param timeout 此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值) + */ + public static void login(Object id, Long timeout) { + stpLogic.login(id, timeout); + } + + /** + * 会话登录,并指定所有登录参数Model + * + * @param id 登录id,建议的类型:(long | int | String) + * @param loginModel 此次登录的参数Model */ public static void login(Object id, SaLoginModel loginModel) { stpLogic.login(id, loginModel); From 4a3f4fa5489863232e4b3fe18afa05e9e60cd6af Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 15 Aug 2022 09:13:39 +0800 Subject: [PATCH 086/144] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index 202d0f0e..00ecd8c5 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -136,7 +136,7 @@ public class StpUtil { * @param id 账号id,建议的类型:(long | int | String) * @param timeout 此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值) */ - public static void login(Object id, Long timeout) { + public static void login(Object id, long timeout) { stpLogic.login(id, timeout); } From 5434ee8800a70e18da420ec4f3da9a45ce4e4632 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 15 Aug 2022 09:14:28 +0800 Subject: [PATCH 087/144] =?UTF-8?q?SSO=E6=A8=A1=E5=9D=97=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=20server-url=20=E5=B1=9E=E6=80=A7=EF=BC=8C=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E5=90=84=E7=A7=8D=20url=20=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/dev33/satoken/strategy/SaStrategy.java | 35 ++++++++++ .../java/com/pj/sso/SsoClientController.java | 4 +- .../cn/dev33/satoken/config/SaSsoConfig.java | 66 +++++++++++++++++-- .../cn/dev33/satoken/sso/SaSsoConsts.java | 3 + .../cn/dev33/satoken/sso/SaSsoTemplate.java | 8 +-- 5 files changed, 103 insertions(+), 13 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java index 657c7bce..9f8e79d5 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java @@ -178,12 +178,36 @@ public final class SaStrategy { // 默认使用jdk的注解处理器 return element.getAnnotation(annotationClass); }; + + /** + * 拼接两个url + *

例如:url1=http://domain.cn,url2=/sso/auth,则返回:http://domain.cn/sso/auth + *

参数 [第一个url, 第二个url] + */ + public BiFunction spliceTwoUrl = (url1, url2) -> { + // q1、任意一个为空,则直接返回另一个 + if(url1 == null) { + return url2; + } + if(url2 == null) { + return url1; + } + + // q2、如果 url2 以 http 开头,将其视为一个完整地址 + if(url2.startsWith("http")) { + return url2; + } + + // q3、将两个地址拼接在一起 + return url1 + url2; + }; // // 重写策略 set连缀风格 // + /** * 重写创建 Token 的策略 *

参数 [账号id, 账号类型] @@ -249,6 +273,17 @@ public final class SaStrategy { this.getAnnotation = getAnnotation; return this; } + + /** + * 拼接两个url + *

例如:url1=http://domain.cn,url2=/sso/auth,则返回:http://domain.cn/sso/auth + *

参数 [第一个url, 第二个url] + * + * @param spliceTwoUrl 要设置的 spliceTwoUrl + */ + public void setSpliceTwoUrl(BiFunction spliceTwoUrl) { + this.spliceTwoUrl = spliceTwoUrl; + } } diff --git a/sa-token-demo/sa-token-demo-sso1-client/src/main/java/com/pj/sso/SsoClientController.java b/sa-token-demo/sa-token-demo-sso1-client/src/main/java/com/pj/sso/SsoClientController.java index da91e2a0..2dbd0c33 100644 --- a/sa-token-demo/sa-token-demo-sso1-client/src/main/java/com/pj/sso/SsoClientController.java +++ b/sa-token-demo/sa-token-demo-sso1-client/src/main/java/com/pj/sso/SsoClientController.java @@ -18,8 +18,8 @@ public class SsoClientController { // SSO-Client端:首页 @RequestMapping("/") public String index() { - String authUrl = SaSsoManager.getConfig().getAuthUrl(); - String solUrl = SaSsoManager.getConfig().getSloUrl(); + String authUrl = SaSsoManager.getConfig().splicingAuthUrl(); + String solUrl = SaSsoManager.getConfig().splicingSloUrl(); String str = "

Sa-Token SSO-Client 应用端

" + "

当前会话是否登录:" + StpUtil.isLogin() + "

" + "

登录 " + diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java index 563d8909..c233f4fb 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java @@ -7,6 +7,7 @@ import java.util.function.Function; import java.util.function.Supplier; import cn.dev33.satoken.exception.SaTokenException; +import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaResult; @@ -53,7 +54,7 @@ public class SaSsoConfig implements Serializable { /** * 配置 Server 端单点登录授权地址 */ - public String authUrl; + public String authUrl = "/sso/auth"; /** * 是否打开单点注销功能 @@ -73,26 +74,30 @@ public class SaSsoConfig implements Serializable { /** * 配置 Server 端的 ticket 校验地址 */ - public String checkTicketUrl; + public String checkTicketUrl = "/sso/checkTicket"; /** * 配置 Server 端查询 userinfo 地址 */ - public String userinfoUrl; + public String userinfoUrl = "/sso/userinfo"; /** * 配置 Server 端单点注销地址 */ - public String sloUrl; + public String sloUrl = "/sso/logout"; /** * 配置当前 Client 端的单点注销回调URL (为空时自动获取) */ public String ssoLogoutCall; + /** + * 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置 + */ + public String serverUrl; // ----------------- 其它 - + /** * 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距 */ @@ -261,6 +266,22 @@ public class SaSsoConfig implements Serializable { return this; } + /** + * @return 配置的 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置 + */ + public String getServerUrl() { + return serverUrl; + } + + /** + * @param serverUrl 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置 + * @return 对象自身 + */ + public SaSsoConfig setServerUrl(String serverUrl) { + this.serverUrl = serverUrl; + return this; + } + /** * @return 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距 */ @@ -276,7 +297,7 @@ public class SaSsoConfig implements Serializable { this.timestampDisparity = timestampDisparity; return this; } - + @Override public String toString() { return "SaSsoConfig [" @@ -290,10 +311,42 @@ public class SaSsoConfig implements Serializable { + ", userinfoUrl=" + userinfoUrl + ", sloUrl=" + sloUrl + ", ssoLogoutCall=" + ssoLogoutCall + + ", serverUrl=" + serverUrl + ", timestampDisparity=" + timestampDisparity + "]"; } + + // 额外添加的一些函数 + + /** + * @return 获取拼接url:Server 端单点登录授权地址 + */ + public String splicingAuthUrl() { + return SaStrategy.me.spliceTwoUrl.apply(getServerUrl(), getAuthUrl()); + } + + /** + * @return 获取拼接url:Server 端的 ticket 校验地址 + */ + public String splicingCheckTicketUrl() { + return SaStrategy.me.spliceTwoUrl.apply(getServerUrl(), getCheckTicketUrl()); + } + + /** + * @return 获取拼接url:Server 端查询 userinfo 地址 + */ + public String splicingUserinfoUrl() { + return SaStrategy.me.spliceTwoUrl.apply(getServerUrl(), getUserinfoUrl()); + } + + /** + * @return 获取拼接url:Server 端单点注销地址 + */ + public String splicingSloUrl() { + return SaStrategy.me.spliceTwoUrl.apply(getServerUrl(), getSloUrl()); + } + /** * 以数组形式写入允许的授权回调地址 * @param url 所有集合 @@ -305,7 +358,6 @@ public class SaSsoConfig implements Serializable { } - // -------------------- SaSsoHandle 所有回调函数 -------------------- diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java index f456f82e..307649f2 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java @@ -22,6 +22,9 @@ public class SaSsoConsts { /** SSO-Server端:校验ticket 获取账号id */ public static String ssoCheckTicket = "/sso/checkTicket"; + /** SSO-Server端:获取userinfo */ + public static String ssoUserinfo = "/sso/userinfo"; + /** SSO-Server端 (and Client端):单点注销地址 */ public static String ssoLogout = "/sso/logout"; diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoTemplate.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoTemplate.java index 6d1c4735..dc7445b6 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoTemplate.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoTemplate.java @@ -253,7 +253,7 @@ public class SaSsoTemplate { public String buildServerAuthUrl(String clientLoginUrl, String back) { // 服务端认证地址 - String serverUrl = SaSsoManager.getConfig().getAuthUrl(); + String serverUrl = SaSsoManager.getConfig().splicingAuthUrl(); // 对back地址编码 back = (back == null ? "" : back); @@ -327,7 +327,7 @@ public class SaSsoTemplate { * @return Server端 账号资料查询地址 */ public String buildUserinfoUrl(Object loginId) { - String userinfoUrl = SaSsoManager.getConfig().getUserinfoUrl(); + String userinfoUrl = SaSsoManager.getConfig().splicingUserinfoUrl(); return addSignParams(userinfoUrl, loginId); } @@ -340,7 +340,7 @@ public class SaSsoTemplate { */ public String buildCheckTicketUrl(String ticket, String ssoLogoutCallUrl) { // 裸地址 - String url = SaSsoManager.getConfig().getCheckTicketUrl(); + String url = SaSsoManager.getConfig().splicingCheckTicketUrl(); // 拼接ticket参数 url = SaFoxUtil.joinParam(url, ParamName.ticket, ticket); @@ -360,7 +360,7 @@ public class SaSsoTemplate { * @return 单点注销URL */ public String buildSloUrl(Object loginId) { - String url = SaSsoManager.getConfig().getSloUrl(); + String url = SaSsoManager.getConfig().splicingSloUrl(); return addSignParams(url, loginId); } From 429303c857cac176187951e54ff5ff81511b8e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=94=E6=98=8E?= <2393584716@qq.com> Date: Mon, 15 Aug 2022 01:17:30 +0000 Subject: [PATCH 088/144] update sa-token-doc/doc/more/join-group.md. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 孔明 <2393584716@qq.com> --- sa-token-doc/doc/more/join-group.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/more/join-group.md b/sa-token-doc/doc/more/join-group.md index 65a0f36a..98c90d8e 100644 --- a/sa-token-doc/doc/more/join-group.md +++ b/sa-token-doc/doc/more/join-group.md @@ -15,6 +15,6 @@ QQ交流群:496757342 [点击加入](https://jq.qq.com/?_wv=1027&k=WNggbsFe) ![微信群](https://oss.dev33.cn/sa-token/wx-qr-300.png ':size=180') -(扫码添加微信,备注:sa-token,邀您加入群聊) +(扫码添加微信,备注:sa,邀您加入群聊) From 9713b4fe26b32623f28ede5c7f51646bdc665f75 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 16 Aug 2022 09:40:16 +0800 Subject: [PATCH 089/144] =?UTF-8?q?SaSession=20=E8=AF=BB=E5=86=99=E5=80=BC?= =?UTF-8?q?=E6=8A=BD=E5=8F=96=E5=85=AC=E5=85=B1=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/session/SaGetValueInterface.java | 202 ++++++++++++ .../cn/dev33/satoken/session/SaSession.java | 290 ++---------------- 2 files changed, 221 insertions(+), 271 deletions(-) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/session/SaGetValueInterface.java diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaGetValueInterface.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaGetValueInterface.java new file mode 100644 index 00000000..cbdb8c09 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaGetValueInterface.java @@ -0,0 +1,202 @@ +package cn.dev33.satoken.session; + +import cn.dev33.satoken.fun.SaRetFunction; +import cn.dev33.satoken.util.SaFoxUtil; + +/** + * 对取值写值的一组方法封装 + * + * @author kong + * @since: 2022-8-16 + */ +public interface SaGetValueInterface { + + // --------- 需要子类实现的方法 + + /** + * 取值 + * @param key key + * @return 值 + */ + public abstract Object get(String key); + + /** + * 写值 + * @param key 名称 + * @param value 值 + * @return 对象自身 + */ + public abstract SaGetValueInterface set(String key, Object value); + + + // --------- 接口提供封装的方法 + + // 取值 + + /** + * + * 取值 (指定默认值) + * @param 默认值的类型 + * @param key key + * @param defaultValue 取不到值时返回的默认值 + * @return 值 + */ + public default T get(String key, T defaultValue) { + return getValueByDefaultValue(get(key), defaultValue); + } + + /** + * + * 取值 (如果值为 null,则执行 fun 函数获取值,并把函数返回值写入缓存) + * @param 返回值的类型 + * @param key key + * @param fun 值为null时执行的函数 + * @return 值 + */ + @SuppressWarnings("unchecked") + public default T get(String key, SaRetFunction fun) { + Object value = get(key); + if(value == null) { + value = fun.run(); + set(key, value); + } + return (T) value; + } + + /** + * 取值 (转String类型) + * @param key key + * @return 值 + */ + public default String getString(String key) { + Object value = get(key); + if(value == null) { + return null; + } + return String.valueOf(value); + } + + /** + * 取值 (转int类型) + * @param key key + * @return 值 + */ + public default int getInt(String key) { + return getValueByDefaultValue(get(key), 0); + } + + /** + * 取值 (转long类型) + * @param key key + * @return 值 + */ + public default long getLong(String key) { + return getValueByDefaultValue(get(key), 0L); + } + + /** + * 取值 (转double类型) + * @param key key + * @return 值 + */ + public default double getDouble(String key) { + return getValueByDefaultValue(get(key), 0.0); + } + + /** + * 取值 (转float类型) + * @param key key + * @return 值 + */ + public default float getFloat(String key) { + return getValueByDefaultValue(get(key), 0.0f); + } + + /** + * 取值 (指定转换类型) + * @param 泛型 + * @param key key + * @param cs 指定转换类型 + * @return 值 + */ + public default T getModel(String key, Class cs) { + return SaFoxUtil.getValueByType(get(key), cs); + } + + /** + * 取值 (指定转换类型, 并指定值为Null时返回的默认值) + * @param 泛型 + * @param key key + * @param cs 指定转换类型 + * @param defaultValue 值为Null时返回的默认值 + * @return 值 + */ + @SuppressWarnings("unchecked") + public default T getModel(String key, Class cs, Object defaultValue) { + Object value = get(key); + if(valueIsNull(value)) { + return (T)defaultValue; + } + return SaFoxUtil.getValueByType(value, cs); + } + + // 写值 & 其它 + + /** + * 写值 (只有在此 key 原本无值的情况下才会写入) + * @param key 名称 + * @param value 值 + * @return 对象自身 + */ + public default SaGetValueInterface setByNull(String key, Object value) { + if(has(key) == false) { + set(key, value); + } + return this; + } + + /** + * 是否含有某个key + * @param key has + * @return 是否含有 + */ + public default boolean has(String key) { + return !valueIsNull(get(key)); + } + + + + + // --------- 内部工具方法 + + /** + * 判断一个值是否为null + * @param value 指定值 + * @return 此value是否为null + */ + public default boolean valueIsNull(Object value) { + return value == null || value.equals(""); + } + + /** + * 根据默认值来获取值 + * @param 泛型 + * @param value 值 + * @param defaultValue 默认值 + * @return 转换后的值 + */ + @SuppressWarnings("unchecked") + public default T getValueByDefaultValue(Object value, T defaultValue) { + + // 如果 obj 为 null,则直接返回默认值 + if(valueIsNull(value)) { + return (T)defaultValue; + } + + // 开始转换 + Class cs = (Class) defaultValue.getClass(); + return SaFoxUtil.getValueByType(value, cs); + } + + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index 734e8d65..e49b97bc 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -10,7 +10,6 @@ import java.util.concurrent.ConcurrentHashMap; import cn.dev33.satoken.SaManager; import cn.dev33.satoken.dao.SaTokenDao; -import cn.dev33.satoken.fun.SaRetFunction; import cn.dev33.satoken.util.SaFoxUtil; /** @@ -19,7 +18,7 @@ import cn.dev33.satoken.util.SaFoxUtil; * @author kong * */ -public class SaSession implements Serializable { +public class SaSession implements SaGetValueInterface, Serializable { /** * @@ -287,139 +286,25 @@ public class SaSession implements Serializable { // ----------------------- 存取值 (类型转换) - // ---- 取值 + // ---- 实现接口存取值方法 + /** - * 取值 + * 取值 * @param key key * @return 值 */ + @Override public Object get(String key) { return dataMap.get(key); } - - /** - * - * 取值 (指定默认值) - * @param 默认值的类型 - * @param key key - * @param defaultValue 取不到值时返回的默认值 - * @return 值 - */ - public T get(String key, T defaultValue) { - return getValueByDefaultValue(get(key), defaultValue); - } /** - * - * 取值 (如果值为null,则执行fun函数获取值) - * @param 返回值的类型 - * @param key key - * @param fun 值为null时执行的函数 - * @return 值 - */ - @SuppressWarnings("unchecked") - public T get(String key, SaRetFunction fun) { - Object value = get(key); - if(value == null) { - value = fun.run(); - set(key, value); - } - return (T) value; - } - - /** - * 取值 (转String类型) - * @param key key - * @return 值 - */ - public String getString(String key) { - Object value = get(key); - if(value == null) { - return null; - } - return String.valueOf(value); - } - - /** - * 取值 (转int类型) - * @param key key - * @return 值 - */ - public int getInt(String key) { - return getValueByDefaultValue(get(key), 0); - } - - /** - * 取值 (转long类型) - * @param key key - * @return 值 - */ - public long getLong(String key) { - return getValueByDefaultValue(get(key), 0L); - } - - /** - * 取值 (转double类型) - * @param key key - * @return 值 - */ - public double getDouble(String key) { - return getValueByDefaultValue(get(key), 0.0); - } - - /** - * 取值 (转float类型) - * @param key key - * @return 值 - */ - public float getFloat(String key) { - return getValueByDefaultValue(get(key), 0.0f); - } - - /** - * 取值 (指定转换类型) - * @param 泛型 - * @param key key - * @param cs 指定转换类型 - * @return 值 - */ - public T getModel(String key, Class cs) { - return SaFoxUtil.getValueByType(get(key), cs); - } - - /** - * 取值 (指定转换类型, 并指定值为Null时返回的默认值) - * @param 泛型 - * @param key key - * @param cs 指定转换类型 - * @param defaultValue 值为Null时返回的默认值 - * @return 值 - */ - @SuppressWarnings("unchecked") - public T getModel(String key, Class cs, Object defaultValue) { - Object value = get(key); - if(valueIsNull(value)) { - return (T)defaultValue; - } - return SaFoxUtil.getValueByType(value, cs); - } - - /** - * 返回当前Session的所有key - * - * @return 所有值的key列表 - */ - public Set keys() { - return dataMap.keySet(); - } - - // ---- 其他 - /** - * 写值 + * 写值 * @param key 名称 * @param value 值 * @return 对象自身 */ + @Override public SaSession set(String key, Object value) { dataMap.put(key, value); update(); @@ -432,6 +317,7 @@ public class SaSession implements Serializable { * @param value 值 * @return 对象自身 */ + @Override public SaSession setByNull(String key, Object value) { if(has(key) == false) { dataMap.put(key, value); @@ -440,15 +326,8 @@ public class SaSession implements Serializable { return this; } - /** - * 是否含有某个key - * @param key has - * @return 是否含有 - */ - public boolean has(String key) { - return !valueIsNull(get(key)); - } - + // ---- 其它方法 + /** * 删值 * @param key 要删除的key @@ -468,6 +347,15 @@ public class SaSession implements Serializable { update(); } + /** + * 返回当前Session的所有key + * + * @return 所有值的key列表 + */ + public Set keys() { + return dataMap.keySet(); + } + /** * 获取数据挂载集合(如果更新map里的值,请调用session.update()方法避免产生脏数据 ) * @@ -487,144 +375,4 @@ public class SaSession implements Serializable { this.update(); } - - // --------- 工具方法 - - /** - * 判断一个值是否为null - * @param value 指定值 - * @return 此value是否为null - */ - public boolean valueIsNull(Object value) { - return value == null || value.equals(""); - } - - /** - * 根据默认值来获取值 - * @param 泛型 - * @param value 值 - * @param defaultValue 默认值 - * @return 转换后的值 - */ - @SuppressWarnings("unchecked") - protected T getValueByDefaultValue(Object value, T defaultValue) { - - // 如果 obj 为 null,则直接返回默认值 - if(valueIsNull(value)) { - return (T)defaultValue; - } - - // 开始转换 - Class cs = (Class) defaultValue.getClass(); - return SaFoxUtil.getValueByType(value, cs); - } - - - - - // ----------------------- 旧API - - /** - *

此函数设计已过时,未来版本可能移除此类,请及时更换为: session.set(key)

- * 写入一个值 - * - * @param key 名称 - * @param value 值 - */ - @Deprecated - public void setAttribute(String key, Object value) { - dataMap.put(key, value); - update(); - } - - /** - *

此函数设计已过时,未来版本可能移除此类,请及时更换为: session.get(key)

- * 取出一个值 - * - * @param key 名称 - * @return 值 - */ - @Deprecated - public Object getAttribute(String key) { - return dataMap.get(key); - } - - /** - *

此函数设计已过时,未来版本可能移除此类,请及时更换为: session.get(key, defaultValue)

- * 取值,并指定取不到值时的默认值 - * - * @param key 名称 - * @param defaultValue 取不到值的时候返回的默认值 - * @return value - */ - @Deprecated - public Object getAttribute(String key, Object defaultValue) { - Object value = getAttribute(key); - if (value != null) { - return value; - } - return defaultValue; - } - - /** - *

此函数设计已过时,未来版本可能移除此类,请及时更换为: session.delete(key)

- * 移除一个值 - * - * @param key 要移除的值的名字 - */ - @Deprecated - public void removeAttribute(String key) { - dataMap.remove(key); - update(); - } - - /** - *

此函数设计已过时,未来版本可能移除此类,请及时更换为: session.clear()

- * 清空所有值 - */ - @Deprecated - public void clearAttribute() { - dataMap.clear(); - update(); - } - - /** - *

此函数设计已过时,未来版本可能移除此类,请及时更换为: session.has(key)

- * 是否含有指定key - * - * @param key 是否含有指定值 - * @return 是否含有 - */ - @Deprecated - public boolean containsAttribute(String key) { - return dataMap.containsKey(key); - } - - /** - *

此函数设计已过时,未来版本可能移除此类,请及时更换为: session.keys()

- * 返回当前session会话所有key - * - * @return 所有值的key列表 - */ - @Deprecated - public Set attributeKeys() { - return dataMap.keySet(); - } - - /** - *

此函数设计已过时,未来版本可能移除此类,请及时更换为: session.setByNull(),用法保持不变

- * 写值(只有在此key原本无值的时候才会写入) - * @param key 名称 - * @param value 值 - * @return 对象自身 - */ - @Deprecated - public SaSession setDefaultValue(String key, Object value) { - if(has(key) == false) { - dataMap.put(key, value); - update(); - } - return this; - } - } From 828f3b82b47dfed7e5e1a1113f08f63c9106ae1a Mon Sep 17 00:00:00 2001 From: AppleOfGray Date: Tue, 16 Aug 2022 08:34:44 +0000 Subject: [PATCH 090/144] =?UTF-8?q?update=20sa-token-doc/doc/fun/token-inf?= =?UTF-8?q?o.md.=20satoken=20=E4=B8=80=E7=BE=A4=20@=E5=90=83=E5=9C=9F99?= =?UTF-8?q?=E5=8F=B7=20=E4=BA=8E=E5=BD=93=E5=89=8D=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E5=8F=91=E7=8E=B0=E7=9A=84=E6=96=87=E6=A1=A3=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/fun/token-info.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/fun/token-info.md b/sa-token-doc/doc/fun/token-info.md index 8de162ae..195d5942 100644 --- a/sa-token-doc/doc/fun/token-info.md +++ b/sa-token-doc/doc/fun/token-info.md @@ -14,7 +14,7 @@ token信息Model: 用来描述一个token的常用参数 "loginType": "login", // 账号类型标识 "tokenTimeout": 2591977, // token剩余有效期 (单位: 秒) "sessionTimeout": 2591977, // User-Session剩余有效时间 (单位: 秒) - "tokenSessionTimeout": -2, // Token-Session剩余有效时间 (单位: 秒) + "tokenSessionTimeout": -2, // Token-Session剩余有效时间 (单位: 秒) (-2表示系统中不存在这个缓存) "tokenActivityTimeout": -1, // token剩余无操作有效时间 (单位: 秒) "loginDevice": "default-device" // 登录设备类型 }, From 823d43b183345e007e5627074bf992fe7253c9e6 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 17 Aug 2022 09:23:37 +0800 Subject: [PATCH 091/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20SaApplication=20?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=EF=BC=8C=E7=94=A8=E4=BA=8E=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E4=BD=9C=E7=94=A8=E5=9F=9F=E5=AD=98=E5=8F=96=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/application/SaApplication.java | 91 +++++++++++++++++++ .../SaGetValueInterface.java | 50 +--------- .../application/SaSetValueInterface.java | 64 +++++++++++++ .../cn/dev33/satoken/context/SaHolder.java | 10 ++ .../cn/dev33/satoken/session/SaSession.java | 24 ++--- 5 files changed, 180 insertions(+), 59 deletions(-) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java rename sa-token-core/src/main/java/cn/dev33/satoken/{session => application}/SaGetValueInterface.java (75%) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/application/SaSetValueInterface.java diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java new file mode 100644 index 00000000..3f10cf37 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java @@ -0,0 +1,91 @@ +package cn.dev33.satoken.application; + +import java.util.ArrayList; +import java.util.List; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.dao.SaTokenDao; + +/** + * Application Model,全局作用域的读取值对象 + * + * @author kong + * @since: 2022-8-17 + */ +public class SaApplication implements SaSetValueInterface { + + /** + * 默认实例 + */ + public static SaApplication defaultInstance = new SaApplication(); + + // ---- 实现接口存取值方法 + + /** 取值 */ + @Override + public Object get(String key) { + return SaManager.getSaTokenDao().getObject(splicingDataKey(key)); + } + + /** 写值 */ + @Override + public SaApplication set(String key, Object value) { + SaManager.getSaTokenDao().setObject(splicingDataKey(key), value, SaTokenDao.NEVER_EXPIRE); + return this; + } + + /** + * 删值 + * @param key 要删除的key + * @return 对象自身 + */ + public SaApplication delete(String key) { + SaManager.getSaTokenDao().deleteObject(splicingDataKey(key)); + return this; + } + + + // ---- 其它方法 + + /** + * 返回存入的所有 key + * @return / + */ + public List keys() { + // 查出来 + String prefix = splicingDataKey(""); + List list = SaManager.getSaTokenDao().searchData(prefix, "", -1, 0, true); + + // 裁减掉固定前缀 + int prefixLength = prefix.length(); + List list2 = new ArrayList<>(); + if(list != null) { + for (String key : list) { + list2.add(key.substring(prefixLength)); + } + } + + // 返回 + return list2; + } + + /** + * 清空存入的所有 key + */ + public void clear() { + List keys = keys(); + for (String key : keys) { + delete(key); + } + } + + /** + * 拼接key:变量存储时使用的key + * @param key 原始 key + * @return 拼接后的 key 值 + */ + public String splicingDataKey(String key) { + return SaManager.getConfig().getTokenName() + ":var:" + key; + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaGetValueInterface.java b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaGetValueInterface.java similarity index 75% rename from sa-token-core/src/main/java/cn/dev33/satoken/session/SaGetValueInterface.java rename to sa-token-core/src/main/java/cn/dev33/satoken/application/SaGetValueInterface.java index cbdb8c09..97bda787 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaGetValueInterface.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaGetValueInterface.java @@ -1,10 +1,9 @@ -package cn.dev33.satoken.session; +package cn.dev33.satoken.application; -import cn.dev33.satoken.fun.SaRetFunction; import cn.dev33.satoken.util.SaFoxUtil; /** - * 对取值写值的一组方法封装 + * 对取值的一组方法封装 * * @author kong * @since: 2022-8-16 @@ -20,19 +19,9 @@ public interface SaGetValueInterface { */ public abstract Object get(String key); - /** - * 写值 - * @param key 名称 - * @param value 值 - * @return 对象自身 - */ - public abstract SaGetValueInterface set(String key, Object value); - // --------- 接口提供封装的方法 - // 取值 - /** * * 取值 (指定默认值) @@ -45,24 +34,6 @@ public interface SaGetValueInterface { return getValueByDefaultValue(get(key), defaultValue); } - /** - * - * 取值 (如果值为 null,则执行 fun 函数获取值,并把函数返回值写入缓存) - * @param 返回值的类型 - * @param key key - * @param fun 值为null时执行的函数 - * @return 值 - */ - @SuppressWarnings("unchecked") - public default T get(String key, SaRetFunction fun) { - Object value = get(key); - if(value == null) { - value = fun.run(); - set(key, value); - } - return (T) value; - } - /** * 取值 (转String类型) * @param key key @@ -140,21 +111,6 @@ public interface SaGetValueInterface { return SaFoxUtil.getValueByType(value, cs); } - // 写值 & 其它 - - /** - * 写值 (只有在此 key 原本无值的情况下才会写入) - * @param key 名称 - * @param value 值 - * @return 对象自身 - */ - public default SaGetValueInterface setByNull(String key, Object value) { - if(has(key) == false) { - set(key, value); - } - return this; - } - /** * 是否含有某个key * @param key has @@ -165,8 +121,6 @@ public interface SaGetValueInterface { } - - // --------- 内部工具方法 /** diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/application/SaSetValueInterface.java b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaSetValueInterface.java new file mode 100644 index 00000000..a7edc991 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaSetValueInterface.java @@ -0,0 +1,64 @@ +package cn.dev33.satoken.application; + +import cn.dev33.satoken.fun.SaRetFunction; + +/** + * 对写值的一组方法封装 + * + * @author kong + * @since: 2022-8-17 + */ +public interface SaSetValueInterface extends SaGetValueInterface { + + // --------- 需要子类实现的方法 + + /** + * 写值 + * @param key 名称 + * @param value 值 + * @return 对象自身 + */ + public abstract SaSetValueInterface set(String key, Object value); + + /** + * 删值 + * @param key 要删除的key + * @return 对象自身 + */ + public abstract SaSetValueInterface delete(String key); + + + // --------- 接口提供封装的方法 + + /** + * + * 取值 (如果值为 null,则执行 fun 函数获取值,并把函数返回值写入缓存) + * @param 返回值的类型 + * @param key key + * @param fun 值为null时执行的函数 + * @return 值 + */ + @SuppressWarnings("unchecked") + public default T get(String key, SaRetFunction fun) { + Object value = get(key); + if(value == null) { + value = fun.run(); + set(key, value); + } + return (T) value; + } + + /** + * 写值 (只有在此 key 原本无值的情况下才会写入) + * @param key 名称 + * @param value 值 + * @return 对象自身 + */ + public default SaSetValueInterface setByNull(String key, Object value) { + if(has(key) == false) { + set(key, value); + } + return this; + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaHolder.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaHolder.java index b6834e34..e1accd9d 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaHolder.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaHolder.java @@ -1,6 +1,7 @@ package cn.dev33.satoken.context; import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.application.SaApplication; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.context.model.SaResponse; import cn.dev33.satoken.context.model.SaStorage; @@ -48,4 +49,13 @@ public class SaHolder { return SaManager.getSaTokenContextOrSecond().getStorage(); } + /** + * 获取全局 SaApplication 对象 + * + * @return see note + */ + public static SaApplication getApplication() { + return SaApplication.defaultInstance; + } + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index e49b97bc..12376c35 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -9,6 +9,7 @@ import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.application.SaSetValueInterface; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.util.SaFoxUtil; @@ -18,7 +19,7 @@ import cn.dev33.satoken.util.SaFoxUtil; * @author kong * */ -public class SaSession implements SaGetValueInterface, Serializable { +public class SaSession implements SaSetValueInterface, Serializable { /** * @@ -286,7 +287,7 @@ public class SaSession implements SaGetValueInterface, Serializable { // ----------------------- 存取值 (类型转换) - // ---- 实现接口存取值方法 + // ---- 重写接口方法 /** * 取值 @@ -326,26 +327,19 @@ public class SaSession implements SaGetValueInterface, Serializable { return this; } - // ---- 其它方法 - /** * 删值 * @param key 要删除的key * @return 对象自身 */ + @Override public SaSession delete(String key) { dataMap.remove(key); update(); return this; } - /** - * 清空所有值 - */ - public void clear() { - dataMap.clear(); - update(); - } + // ---- 其它方法 /** * 返回当前Session的所有key @@ -356,6 +350,14 @@ public class SaSession implements SaGetValueInterface, Serializable { return dataMap.keySet(); } + /** + * 清空所有值 + */ + public void clear() { + dataMap.clear(); + update(); + } + /** * 获取数据挂载集合(如果更新map里的值,请调用session.update()方法避免产生脏数据 ) * From 4374c0fa771647aace5447c9a007db9cde9f897f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=81=E8=A8=80=E7=89=A9=E8=AF=AD?= Date: Wed, 17 Aug 2022 01:42:29 +0000 Subject: [PATCH 092/144] =?UTF-8?q?update=20sa-token-doc/doc/oauth2/oauth2?= =?UTF-8?q?-api.md.=20=E4=BF=AE=E6=94=B9=202=E3=80=81=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=BA=8C=EF=BC=9A=E9=9A=90=E8=97=8F=E5=BC=8F=EF=BC=88Implicit?= =?UTF-8?q?=EF=BC=89=20url=20=E5=AD=97=E7=AC=A6=E9=94=99=E8=AF=AF=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20$=20->=20&?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 码言物语 --- sa-token-doc/doc/oauth2/oauth2-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/oauth2/oauth2-api.md b/sa-token-doc/doc/oauth2/oauth2-api.md index 7d1db796..52009a9a 100644 --- a/sa-token-doc/doc/oauth2/oauth2-api.md +++ b/sa-token-doc/doc/oauth2/oauth2-api.md @@ -14,7 +14,7 @@ http://sa-oauth-server.com:8001/oauth2/authorize &client_id={value} &redirect_uri={value} &scope={value} - $state={value} + &state={value} ``` 参数详解: From 6a59d2f2a23adce4f3fb55f4fa3066512342c44a Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 17 Aug 2022 10:28:27 +0800 Subject: [PATCH 093/144] =?UTF-8?q?=E6=B7=BB=E5=8A=A0demo=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E8=BF=90=E8=A1=8C=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/start/download.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/sa-token-doc/doc/start/download.md b/sa-token-doc/doc/start/download.md index 0cdb8f83..8d72f53f 100644 --- a/sa-token-doc/doc/start/download.md +++ b/sa-token-doc/doc/start/download.md @@ -147,8 +147,14 @@ implementation 'cn.dev33:sa-token-core:${sa.top.version}' 注:JDK版本:`v1.8+`,SpringBoot:`建议2.0以上` +## jar包下载 +[点击下载:sa-token-1.6.0.jar](https://oss.dev33.cn/sa-token/sa-token-1.6.0.jar) + +注:当前仅提供 `v1.6.0` 版本jar包下载,更多版本请前往 maven 中央仓库获取,[直达链接](https://search.maven.org/search?q=sa-token) + + ## 获取源码 -如果你想深入了解Sa-Token,你可以通过`Gitee`或者`GitHub`来获取源码 (**学习测试请拉取master分支**,dev为正在开发的分支,有很多特性并不稳定) +如果你想深入了解 Sa-Token,你可以通过`Gitee`或者`GitHub`来获取源码 (**学习测试请拉取 master 分支**,dev为正在开发的分支,有很多特性并不稳定) - **Gitee**地址:[https://gitee.com/dromara/sa-token](https://gitee.com/dromara/sa-token) - **GitHub**地址:[https://github.com/dromara/sa-token](https://github.com/dromara/sa-token) - 开源不易,求鼓励,给个`star`吧 @@ -207,11 +213,10 @@ implementation 'cn.dev33:sa-token-core:${sa.top.version}' +## 运行示例 -## jar包下载 -[点击下载:sa-token-1.6.0.jar](https://oss.dev33.cn/sa-token/sa-token-1.6.0.jar) - -注:当前仅提供 `v1.6.0` 版本jar包下载,更多版本请前往 maven 中央仓库获取,[直达链接](https://search.maven.org/search?q=sa-token) - - +- 1、下载代码(学习测试用 master 分支)。 +- 2、从根目录导入项目。 +- 3、选择相应的示例添加为 Maven 项目,打开 XxxApplication.java 运行。 +![运行示例](https://oss.dev33.cn/sa-token/doc/import-demo-run.png 's-w-sh') \ No newline at end of file From 53a9d5bea675818cf6f055874a564921b7ec5862 Mon Sep 17 00:00:00 2001 From: AppleOfGray Date: Wed, 17 Aug 2022 03:00:06 +0000 Subject: [PATCH 094/144] =?UTF-8?q?update=20sa-token-doc/doc/more/common-q?= =?UTF-8?q?uestions.md.=20=E7=BE=A4=E9=87=8C=E9=97=AE=E4=BA=86=E5=A5=BD?= =?UTF-8?q?=E5=87=A0=E6=AC=A1=E4=BA=86...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/common-questions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sa-token-doc/doc/more/common-questions.md b/sa-token-doc/doc/more/common-questions.md index 1baefb33..7954cd42 100644 --- a/sa-token-doc/doc/more/common-questions.md +++ b/sa-token-doc/doc/more/common-questions.md @@ -37,6 +37,8 @@ 3. 如果是 WebFlux 环境而且正确引入了依赖,依然报错,请检查是否注册了全局过滤器,在 WebFlux 下这一步是必须的。 4. 如果以上步骤排除无误后依然报错,请直接提 issues 或者加入QQ群求助。 +> 提示: zuul 网关是 SpringMVC 环境, spring cloud gateway 网关是 WebFlux 环境 + ### 报错:NotLoginException:xxx 这个错是说明调用接口的人没有通过登录认证,请注意通常**异常提示语已经描述清楚了没有通过认证的具体原因**,例如:没有提供Token、提供的Token是无效的、提供的Token已经过期……等等 From 409ae8014a41763e56d7875b9c4e75f558a758b6 Mon Sep 17 00:00:00 2001 From: AppleOfGray Date: Wed, 17 Aug 2022 05:37:27 +0000 Subject: [PATCH 095/144] =?UTF-8?q?update=20sa-token-doc/doc/use/session.m?= =?UTF-8?q?d.=20=E6=96=87=E6=A1=A3=E4=B8=AD=E6=9C=89=E8=BF=99=E4=B8=AA?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E7=9A=84=E4=BD=BF=E7=94=A8,=20=E4=BD=86?= =?UTF-8?q?=E6=98=AF=E6=B2=A1=E6=9C=89=E6=8F=90=E5=89=8D=E8=AF=B4=E6=98=8E?= =?UTF-8?q?=20https://sa-token.dev33.cn/doc/index.html#/fun/jur-cache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/use/session.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sa-token-doc/doc/use/session.md b/sa-token-doc/doc/use/session.md index 6ace86c7..dfe92d54 100644 --- a/sa-token-doc/doc/use/session.md +++ b/sa-token-doc/doc/use/session.md @@ -86,6 +86,11 @@ session.get("name"); // 取值 (指定默认值) session.get("name", ""); +// 取值 (若无值则执行参数方法, 之后将结果保存到此键名下,并返回此结果 若有值则直接返回, 无需执行参数方法) +session.get("name", () -> { + return ...; + }); + // ---------- 数据类型转换: ---------- session.getInt("age"); // 取值 (转int类型) session.getLong("age"); // 取值 (转long类型) From 4a9fd145cb61767218061e17ef968130abc9a8d7 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 17 Aug 2022 23:26:03 +0800 Subject: [PATCH 096/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/fun/timeline.md | 22 +++++++++++++--------- sa-token-doc/doc/lib/index.css | 9 ++++++++- sa-token-doc/doc/more/noun-intro.md | 4 ++-- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/sa-token-doc/doc/fun/timeline.md b/sa-token-doc/doc/fun/timeline.md index d62c91dd..7bc151a1 100644 --- a/sa-token-doc/doc/fun/timeline.md +++ b/sa-token-doc/doc/fun/timeline.md @@ -1,5 +1,6 @@ # Sa-Token 开源大事记 +--- - **2020-02-04:** 在 GitHub 提交第一个版本,正式开源。 - **2020-09-14:** GitHub star 数量破 100。 @@ -9,18 +10,21 @@ - **2021-03-30:** 受 TLog 作者邀请,Sa-Token 加入 dromara 社区。 - **2021-03-30:** 被 Gitee 列为推荐项目。 - **2021-03-31:** Gitee star 数量破1K。 -- **2021-04-09:** GitHub star 数量破2K。 -- **2021-05-09:** Gitee star 数量破2K。 -- **2021-05-17:** GitHub star 数量破3K。 + + + - **2021-06-17:** Sa-Token star 数量 (3529) 超过 Shiro (3506)。 -- **2021-07-15:** GitHub star 数量破4K。 + - **2021-07-26:** GitHub star 数量破5K。 -- **2021-07-29:** Gitee star 数量破3K。 -- **2021-09-07:** GitHub star 数量破6K。 + + - **2021-09-24:** Sa-Token star 数量 (6280) 超过 SpringSecurity (6247)。 -- **2021-10-19:** Gitee star 数量破4K。 + - **2021-11-08:** 荣获开源中国 “码云 GVP 认证”。 -- **2021-11-17:** GitHub star 数量破7K。 + - **2021-11-28:** Gitee star 数量破5K。 +- **2021-12-27:** 荣获 OSC-2021 最佳软件 Top 30。 +- **2022-05-20:** 成为 [可信开源社区共同体] 预备成员。 +- **2022-08-01:** 加入 [中国开源社区 landscape]。 + - diff --git a/sa-token-doc/doc/lib/index.css b/sa-token-doc/doc/lib/index.css index fa1b6797..f8deb9e2 100644 --- a/sa-token-doc/doc/lib/index.css +++ b/sa-token-doc/doc/lib/index.css @@ -232,4 +232,11 @@ body { border-bottom: 2px var(--a-color) solid; transition: all 0.2s; } -.doc-header .nav-right .wzi:hover::after {width: 100%;} */ \ No newline at end of file +.doc-header .nav-right .wzi:hover::after {width: 100%;} */ + + +/* 保证点开图片时在最上面 */ +.medium-zoom-image.medium-zoom-image--opened{ + z-index: 10000; +} + diff --git a/sa-token-doc/doc/more/noun-intro.md b/sa-token-doc/doc/more/noun-intro.md index a638d5a8..21afced6 100644 --- a/sa-token-doc/doc/more/noun-intro.md +++ b/sa-token-doc/doc/more/noun-intro.md @@ -1,9 +1,9 @@ # Sa-Token 名词解释 -Sa-Token 无意发明任何晦涩概念提升逼格,但在处理 issues 、Q群解答时还是发现不少同学因为一些基本概念理解偏差导致代码出错, +Sa-Token 无意发明任何晦涩概念提升逼格,但在处理 issue 、Q群解答时还是发现不少同学因为一些基本概念理解偏差导致代码出错, 所以整理本篇针对一些比较容易混淆的地方加以解释说明。 -也希望各位同学在提交 issues、Q群提问之前充分阅读本篇文章,保证不要因为基本概念理解偏差,增加不必要的沟通成本。 +也希望各位同学在提交 issue、Q群提问之前充分阅读本篇文章,保证不要因为基本概念理解偏差,增加不必要的沟通成本。 --- From 7a308cd88c6c7ebb13fe0076818a551675aca792 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 17 Aug 2022 23:26:28 +0800 Subject: [PATCH 097/144] =?UTF-8?q?SaApplication=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=9C=89=E6=95=88=E6=9C=9F=E5=86=99=E5=85=A5=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev33/satoken/application/SaApplication.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java index 3f10cf37..324ead9e 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java @@ -30,8 +30,7 @@ public class SaApplication implements SaSetValueInterface { /** 写值 */ @Override public SaApplication set(String key, Object value) { - SaManager.getSaTokenDao().setObject(splicingDataKey(key), value, SaTokenDao.NEVER_EXPIRE); - return this; + return set(key, value, SaTokenDao.NEVER_EXPIRE); } /** @@ -47,6 +46,18 @@ public class SaApplication implements SaSetValueInterface { // ---- 其它方法 + /** + * 写值 + * @param key 名称 + * @param value 值 + * @param ttl 有效时间(单位:秒) + * @return 对象自身 + */ + public SaApplication set(String key, Object value, long ttl) { + SaManager.getSaTokenDao().setObject(splicingDataKey(key), value, ttl); + return this; + } + /** * 返回存入的所有 key * @return / From 07fadc2747c7aef712916e975ca82d39984a2a7b Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 18 Aug 2022 17:30:21 +0800 Subject: [PATCH 098/144] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=AF=B9=E8=B1=A1=E6=97=B6=E5=BB=BA=E8=AE=AE?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/dev33/satoken/session/SaSession.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index 12376c35..06375388 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -25,7 +25,12 @@ public class SaSession implements SaSetValueInterface, Serializable { * */ private static final long serialVersionUID = 1L; - + + /** + * 在 Session 上存储用户对象时建议使用的key + */ + public static final String USER = "USER"; + /** * 在 Session 上存储角色时建议使用的key */ From f4f06c45168931a264d81dd3f1e795241bef426c Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 18 Aug 2022 17:30:49 +0800 Subject: [PATCH 099/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20getStpLogic()=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/dev33/satoken/stp/StpUtil.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index 00ecd8c5..8993e7c9 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -45,6 +45,14 @@ public class StpUtil { // 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic SaManager.putStpLogic(newStpLogic); } + + /** + * 获取 StpLogic 对象 + * @return / + */ + public static StpLogic getStpLogic() { + return stpLogic; + } // =================== 获取token 相关 =================== From a1f9d1f461d58742f22f6501a4f12b569309f446 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 18 Aug 2022 17:31:10 +0800 Subject: [PATCH 100/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java index cc089c86..90bf2248 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java @@ -218,7 +218,7 @@ public class SaManager { public static Map stpLogicMap = new HashMap(); /** - * 向集合中 put 一个 StpLogic + * 向全局集合中 put 一个 StpLogic * @param stpLogic StpLogic */ public static void putStpLogic(StpLogic stpLogic) { From c07ada067ad6329e4ede8f255dacccbf66c85aa6 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 18 Aug 2022 17:32:08 +0800 Subject: [PATCH 101/144] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20getStpLogic()=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/pj/satoken/at/StpUserUtil.java | 8 ++++++++ .../src/main/java/com/pj/satoken/at/StpUserUtil.java | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java index db173bd3..1e697e67 100644 --- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java +++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java @@ -48,6 +48,14 @@ public class StpUserUtil { // 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic SaManager.putStpLogic(newStpLogic); } + + /** + * 获取 StpLogic 对象 + * @return / + */ + public static StpLogic getStpLogic() { + return stpLogic; + } // =================== 获取token 相关 =================== diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java index db173bd3..1e697e67 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java @@ -48,6 +48,14 @@ public class StpUserUtil { // 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic SaManager.putStpLogic(newStpLogic); } + + /** + * 获取 StpLogic 对象 + * @return / + */ + public static StpLogic getStpLogic() { + return stpLogic; + } // =================== 获取token 相关 =================== From a12058b18dbd42ce513288b39b3ba587a6ef5045 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 18 Aug 2022 17:40:18 +0800 Subject: [PATCH 102/144] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=BC=80=E6=BA=90?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/fun/timeline.md | 1 + 1 file changed, 1 insertion(+) diff --git a/sa-token-doc/doc/fun/timeline.md b/sa-token-doc/doc/fun/timeline.md index 7bc151a1..f5e60236 100644 --- a/sa-token-doc/doc/fun/timeline.md +++ b/sa-token-doc/doc/fun/timeline.md @@ -26,5 +26,6 @@ - **2021-12-27:** 荣获 OSC-2021 最佳软件 Top 30。 - **2022-05-20:** 成为 [可信开源社区共同体] 预备成员。 - **2022-08-01:** 加入 [中国开源社区 landscape]。 +- **2021-08-18:** GitHub 第 10000 个 star 里程碑! From e846e80dce4530680e7a8453076434f7b2eb9e61 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 18 Aug 2022 17:41:01 +0800 Subject: [PATCH 103/144] =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=B7=BB=E5=8A=A0API?= =?UTF-8?q?=E6=89=8B=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/_sidebar.md | 9 +- sa-token-doc/doc/api/sa-session.md | 77 +++++++++++ sa-token-doc/doc/api/sa-strategy.md | 74 ++++++++++ sa-token-doc/doc/api/sa-token-dao.md | 61 +++++++++ sa-token-doc/doc/api/stp-util.md | 179 +++++++++++++++++++++++++ sa-token-doc/doc/more/common-action.md | 55 ++++++-- 6 files changed, 440 insertions(+), 15 deletions(-) create mode 100644 sa-token-doc/doc/api/sa-session.md create mode 100644 sa-token-doc/doc/api/sa-strategy.md create mode 100644 sa-token-doc/doc/api/sa-token-dao.md create mode 100644 sa-token-doc/doc/api/stp-util.md diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 3e3e024c..c0e35b0e 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -70,6 +70,14 @@ - [和 Dubbo 集成](/plugin/dubbo-extend) - [Sa-Token 插件开发指南](/fun/plugin-dev) +- **API手册** + - [StpUtil-鉴权工具类](/api/stp-util) + - [SaSession-会话对象](/api/sa-session) + - [SaTokenDao-数据持久接口](/api/sa-token-dao) + - [SaStrategy-全局策略](/api/sa-strategy) + - [全局类、方法](/more/common-action) + + - **其它** - [更新日志](/more/update-log) - [框架生态](/more/link) @@ -79,7 +87,6 @@ - [赞助 Sa-Token](/more/sa-token-donate) - **附录** - - [常用类、方法](/more/common-action) - [常见问题排查](/more/common-questions) - [框架名词解释](/more/noun-intro) - [Sa-Token功能结构图](/fun/auth-flow) diff --git a/sa-token-doc/doc/api/sa-session.md b/sa-token-doc/doc/api/sa-session.md new file mode 100644 index 00000000..6c210773 --- /dev/null +++ b/sa-token-doc/doc/api/sa-session.md @@ -0,0 +1,77 @@ +# SaSession-会话对象 + +SaSession-会话对象,专业数据缓存组件。 + +--- + +### 1、常量 +``` java +SaSession.ROLE_LIST = "USER"; // 在 Session 上存储用户对象时建议使用的key +SaSession.ROLE_LIST = "ROLE_LIST"; // 在 Session 上存储角色时建议使用的key +SaSession.PERMISSION_LIST = "PERMISSION_LIST"; // 在 Session 上存储权限时建议使用的key +``` + + +### 2、构建相关 +``` java +session.getId(); // 获取此 Session 的 id +session.setId(id); // 写入此 Session 的 id +session.getCreateTime(); // 返回当前会话创建时间(时间戳) +session.setCreateTime(createTime); // 写入此 Session 的创建时间(时间戳) +``` + + +### 3、TokenSign 相关 +``` java +session.setTokenSignList(tokenSignList); // 写入此 Session 绑定的 Token 签名列表 +session.getTokenSignList(); // 获取此 Session 绑定的 Token 签名列表 +session.tokenSignListCopy(); // 获取 Token 签名列表 的拷贝副本 +session.tokenSignListCopyByDevice(device); // 返回 Token 签名列表 的拷贝副本,根据 device 筛选 +session.getTokenSign(tokenValue); // 查找一个 Token 签名 +session.addTokenSign(tokenSign); // 添加一个 Token 签名 +session.addTokenSign(tokenValue, device); // 添加一个 Token 签名 +session.removeTokenSign(tokenValue); // 移除一个 Token 签名 +``` + + +### 4、一些操作 +``` java +session.update(); // 更新Session(从持久库更新刷新一下) +session.logout(); // 注销Session (从持久库删除) +session.logoutByTokenSignCountToZero(); // 当Session上的tokenSign数量为零时,注销会话 +session.getTimeout(); // 获取此Session的剩余存活时间 (单位: 秒) +session.updateTimeout(timeout); // 修改此Session的剩余存活时间 +session.updateMinTimeout(minTimeout); // 修改此Session的最小剩余存活时间 (只有在 Session 的过期时间低于指定的 minTimeout 时才会进行修改) +session.updateMaxTimeout(maxTimeout); // 修改此Session的最大剩余存活时间 (只有在 Session 的过期时间高于指定的 maxTimeout 时才会进行修改) +session.trans(value); // value为 -1 时返回 Long.MAX_VALUE,否则原样返回 +``` + + +### 5、存取值 +``` java +session.get(key); // 取值 +session.get(key, defaultValue); // 取值 (指定默认值) +session.get(key, () -> {}); // 取值 (如果值为 null,则执行 fun 函数获取值,并把函数返回值写入缓存) +session.getString(key); // 取值 (转String类型) +session.getInt(key); // 取值 (转int类型) +session.getLong(key); // 取值 (转long类型) +session.getDouble(key); // 取值 (转double类型) +session.getFloat(key); // 取值 (转float类型) +session.getModel(key, clazz); // 取值 (指定转换类型) +session.getModel(key, clazz, defaultValue); // 取值 (指定转换类型, 并指定值为Null时返回的默认值) +session.has(key); // 是否含有某个key +session.set(key, value); // 写值 +session.setByNull(key, value); // 写值 (只有在此 key 原本无值的情况下才会写入) +session.delete(key); // 删值 +session.keys(); // 返回当前Session的所有key +session.clear(); // 清空所有值 +session.getDataMap(); // 获取数据挂载集合(如果更新map里的值,请调用session.update()方法避免产生脏数据 ) +session.refreshDataMap(dataMap); // 写入数据集合 (不改变底层对象,只将此dataMap所有数据进行替换) +``` + + + + + + + diff --git a/sa-token-doc/doc/api/sa-strategy.md b/sa-token-doc/doc/api/sa-strategy.md new file mode 100644 index 00000000..7529e8cb --- /dev/null +++ b/sa-token-doc/doc/api/sa-strategy.md @@ -0,0 +1,74 @@ +# SaStrategy-全局策略 + +SaStrategy-全局策略,核心逻辑的代理封装。 + +--- + +### 所有策略 + +``` java +/** + * 创建 Token 的策略 + *

参数 [账号id, 账号类型] + */ +public BiFunction createToken = (loginId, loginType) -> { + // 默认,还是uuid + return "xxxxx-xxxxx-xxxxx-xxxxx"; +}; + +/** + * 创建 Session 的策略 + *

参数 [SessionId] + */ +public Function createSession = (sessionId) -> { + return new SaSession(sessionId); +}; + +/** + * 判断:集合中是否包含指定元素(模糊匹配) + *

参数 [集合, 元素] + */ +public BiFunction, String, Boolean> hasElement = (list, element) -> { + return false; +}; + +/** + * 对一个 [Method] 对象进行注解校验 (注解鉴权内部实现) + *

参数 [Method句柄] + */ +public Consumer checkMethodAnnotation = (method) -> { + // ... +}; + +/** + * 对一个 [元素] 对象进行注解校验 (注解鉴权内部实现) + *

参数 [element元素] + */ +public Consumer checkElementAnnotation = (target) -> { + // ... +}; + +/** + * 从元素上获取注解(注解鉴权内部实现) + *

参数 [element元素,要获取的注解类型] + */ +public BiFunction , Annotation> getAnnotation = (element, annotationClass)->{ + // 默认使用jdk的注解处理器 + return element.getAnnotation(annotationClass); +}; + +/** + * 拼接两个url + *

例如:url1=http://domain.cn,url2=/sso/auth,则返回:http://domain.cn/sso/auth + *

参数 [第一个url, 第二个url] + */ +public BiFunction spliceTwoUrl = (url1, url2) -> { + return xxx; +}; +``` + + + + + + diff --git a/sa-token-doc/doc/api/sa-token-dao.md b/sa-token-doc/doc/api/sa-token-dao.md new file mode 100644 index 00000000..a2d95292 --- /dev/null +++ b/sa-token-doc/doc/api/sa-token-dao.md @@ -0,0 +1,61 @@ +# SaTokenDao-数据持久接口 + +SaTokenDao 是数据持久层接口,负责所有会话数据的底层写入和读取。 + +--- + +### 1、常量 +``` java +SaTokenDao.NEVER_EXPIRE = -1; // 常量,表示一个key永不过期 (在一个key被标注为永远不过期时返回此值) +SaTokenDao.NOT_VALUE_EXPIRE = -2; // 常量,表示系统中不存在这个缓存 (在对不存在的key获取剩余存活时间时返回此值) +``` + + +### 2、字符串读写 +``` java +dao.get(key); // 获取Value,如无返空 +dao.set(key, value, timeout); // 写入Value,并设定存活时间 (单位: 秒) +dao.update(key, value); // 更新Value (过期时间不变) +dao.delete(key); // 删除Value +dao.getTimeout(key); // 获取Value的剩余存活时间 (单位: 秒) +dao.updateTimeout(key, timeout); // 修改Value的剩余存活时间 (单位: 秒) +``` + + +### 3、对象读写 +``` java +dao.getObject(key); // 获取Object,如无返空 +dao.setObject(key, value, timeout); // 写入Object,并设定存活时间 (单位: 秒) +dao.setObject(key, value); // 更新Object (过期时间不变) +dao.deleteObject(key); // 删除Object +dao.getObjectTimeout(key); // 获取Object的剩余存活时间 (单位: 秒) +dao.updateObjectTimeout(key, timeout); // 修改Object的剩余存活时间 (单位: 秒) +``` + + +### 4、Session读写 +``` java +dao.getSession(sessionId); // 获取Session,如无返空 +dao.setSession(session, timeout); // 写入Session,并设定存活时间 (单位: 秒) +dao.setSession(session); // 更新Session (过期时间不变) +dao.deleteSession(sessionId); // 删除Session +dao.getSessionTimeout(sessionId); // 获取Session的剩余存活时间 (单位: 秒) +dao.updateSessionTimeout(sessionId, timeout); // 修改Session的剩余存活时间 (单位: 秒) +``` + + +### 5、会话管理 +``` java +dao.searchData(prefix, keyword, start, size, sortType); // 搜索数据 +``` + + + + + + + + + + + diff --git a/sa-token-doc/doc/api/stp-util.md b/sa-token-doc/doc/api/stp-util.md new file mode 100644 index 00000000..2e7ee315 --- /dev/null +++ b/sa-token-doc/doc/api/stp-util.md @@ -0,0 +1,179 @@ +# StpUtil - 鉴权工具类 + +StpUtil 是 Sa-Token 整体功能的核心,大多数功能均由此工具类提供。 + +--- + +### 1、常规操作 +``` java +StpUtil.getStpLogic(); // 获取底层 StpLogic 对象。 +StpUtil.setStpLogic(newStpLogic); // 安全的重置底层 StpLogic 引用。 +StpUtil.getLoginType(); // 获取账号类型 (例如:login、user、admin、teacher、student等等)。 +StpUtil.getTokenName(); // 获取 Token 的名称 +StpUtil.getTokenValue(); // 获取本次请求前端提交的 Token。 +StpUtil.getTokenValueNotCut(); // 获取本次请求前端提交的 Token (不裁剪前缀) 。 +StpUtil.setTokenValue(tokenValue); // 在当前会话中写入 Token 值。 +StpUtil.setTokenValue(tokenValue, timeout); // 在当前会话中写入 Token 值,并指定 Cookie 有效期。 +StpUtil.getTokenInfo(); // 获取当前 Token 的详细参数。 +``` + + +### 2、登录相关 +``` java +StpUtil.login(10001); // 会话登录 +StpUtil.login(10001, "APP"); // 会话登录,并指定设备类型 +StpUtil.login(10001, true); // 会话登录,并指定是否 [记住我] +StpUtil.login(10001, loginModel); // 会话登录,并指定所有登录参数Model +StpUtil.createLoginSession(10001); // 创建指定账号id的登录会话,此方法不会将 Token 注入到上下文 +StpUtil.createLoginSession(10001, loginModel); // 创建指定账号id的登录会话,此方法不会将 Token 注入到上下文 +``` + +SaLoginModel 配置示例: +``` java +// SaLoginModel 配置登录相关参数 +StpUtil.login(10001, new SaLoginModel() + .setDevice("PC") // 此次登录的客户端设备类型, 用于[同端互斥登录]时指定此次登录的设备类型 + .setIsLastingCookie(true) // 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在) + .setTimeout(60 * 60 * 24 * 7) // 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的 timeout 值) + .setToken("xxxx-xxxx-xxxx-xxxx") // 预定此次登录生成的Token + .setExtra("name", "zhangsan") // Token挂载的扩展参数 (此方法只有在集成jwt插件时才会生效) + ); +``` + + +### 3、注销相关 +``` java +StpUtil.logout(); // 会话注销 +StpUtil.logout(10001); // 会话注销,根据账号id +StpUtil.logout(10001, "PC"); // 会话注销,根据账号id 和 设备类型 +StpUtil.logoutByTokenValue(token); // 指定 Token 强制注销 +StpUtil.kickout(10001); // 踢人下线 +StpUtil.kickout(10001, "PC"); // 踢人下线,根据账号id +StpUtil.kickoutByTokenValue(token); // 踢人下线,根据账号id 和 设备类型 +``` + + +### 4、会话查询 +``` java +StpUtil.isLogin(); // 当前会话是否已经登录 +StpUtil.checkLogin(); // 检验当前会话是否已经登录,如未登录,则抛出异常 +StpUtil.getLoginId(); // 获取当前会话账号id, 如果未登录,则抛出异常 +StpUtil.getLoginId(defaultValue); // 获取当前会话账号id, 如果未登录,则返回默认值 +StpUtil.getLoginIdDefaultNull(); // 获取当前会话账号id, 如果未登录,则返回null +StpUtil.getLoginIdAsString(); // 获取当前会话账号id, 并转换为String类型 +StpUtil.getLoginIdAsInt(); // 获取当前会话账号id, 并转换为int类型 +StpUtil.getLoginIdAsLong(); // 获取当前会话账号id, 并转换为long类型 +StpUtil.getLoginIdByToken(token); // 获取指定Token对应的账号id,如果未登录,则返回 null +StpUtil.getExtra(key); // 获取当前 Token 的扩展信息(此函数只在jwt模式下生效) +StpUtil.getExtra(token, key); // 获取指定 Token 的扩展信息(此函数只在jwt模式下生效) +``` + + +### 5、Session 相关 +``` java +// User-Session 相关 +StpUtil.getSession(); // 获取当前会话的Session,如果Session尚未创建,则新建并返回 +StpUtil.getSession(true); // 获取当前会话的Session, 如果Session尚未创建,isCreate=是否新建并返回 +StpUtil.getSessionByLoginId(10001); // 获取指定账号id的Session,如果Session尚未创建,则新建并返回 +StpUtil.getSessionByLoginId(10001, true); // 获取指定账号id的Session, 如果Session尚未创建,isCreate=是否新建并返回 + +// Token-Session 相关 +StpUtil.getTokenSession(); // 获取当前会话的Session,如果Session尚未创建,则新建并返回 +StpUtil.getTokenSessionByToken(token); // 获取指定Token-Session,如果Session尚未创建,则新建并返回 +StpUtil.getAnonTokenSession(); // 获取当前匿名 Token-Session (可在未登录情况下使用的Token-Session) + +// 其它 +StpUtil.getSessionBySessionId("xxxx-xxxx-xxxx"); // 获取指定key的Session, 如果Session尚未创建,则返回 null +``` + + +### 6、Token有效期相关 +``` java +// 临时有效期 +StpUtil.getTokenActivityTimeout(); // 获取当前 token [临时过期] 剩余有效时间 (单位: 秒) +StpUtil.checkActivityTimeout(); // 检查当前token 是否已经[临时过期],如果已经过期则抛出异常 +StpUtil.updateLastActivityToNow(); // 续签当前token:(将 [最后操作时间] 更新为当前时间戳) + +// 长久有效期 +StpUtil.getTokenTimeout(); // 获取当前登录者的 token 剩余有效时间 (单位: 秒) +StpUtil.getSessionTimeout(); // 获取当前登录者的 User-Session 剩余有效时间 (单位: 秒) +StpUtil.getTokenSessionTimeout(); // 获取当前 Token-Session 剩余有效时间 (单位: 秒) +StpUtil.renewTimeout(timeout); // 对当前 Token 的 timeout 值进行续期 +StpUtil.renewTimeout(token, timeout); // 对指定 Token 的 timeout 值进行续期 +``` + + +### 7、角色认证 +``` java +StpUtil.getRoleList(); // 获取:当前账号的角色集合 +StpUtil.getRoleList(10001); // 获取:指定账号的角色集合 +StpUtil.hasRole(role); // 判断:当前账号是否拥有指定角色, 返回true或false +StpUtil.hasRole(loginId, role); // 判断:指定账号是否含有指定角色标识, 返回true或false +StpUtil.hasRoleAnd(...roleArray); // 判断:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] +StpUtil.hasRoleOr(...roleArray); // 判断:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] +StpUtil.checkRole(role); // 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException +StpUtil.checkRoleAnd(...roleArray); // 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] +StpUtil.checkRoleOr(...roleArray); // 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] +``` + + +### 8、权限认证 +``` java +StpUtil.getPermissionList(); // 获取:当前账号的权限集合 +StpUtil.getPermissionList(10001); // 获取:指定账号的权限集合 +StpUtil.hasPermission(permission); // 判断:当前账号是否拥有指定权限, 返回true或false +StpUtil.hasPermission(loginId, permission); // 判断:指定账号是否含有指定权限标识, 返回true或false +StpUtil.hasPermissionAnd(...permissionArray); // 判断:当前账号是否含有指定权限标识 [指定多个,必须全部验证通过] +StpUtil.hasPermissionOr(...permissionArray); // 判断:当前账号是否含有指定权限标识 [指定多个,只要其一验证通过即可] +StpUtil.checkPermission(permission); // 校验:当前账号是否含有指定权限标识, 如果验证未通过,则抛出异常: NotRoleException +StpUtil.checkPermissionAnd(...permissionArray); // 校验:当前账号是否含有指定权限标识 [指定多个,必须全部验证通过] +StpUtil.checkPermissionOr(...permissionArray); // 校验:当前账号是否含有指定权限标识 [指定多个,只要其一验证通过即可] +``` + + +### 9、id 反查 Token +``` java +StpUtil.getTokenValueByLoginId(10001); // 获取指定账号id的tokenValue +StpUtil.getTokenValueByLoginId(10001, "PC"); // 获取指定账号id指定设备类型端的tokenValue +StpUtil.getTokenValueListByLoginId(10001); // 获取指定账号id的tokenValue集合 +StpUtil.getTokenValueListByLoginId(10001, "APP"); // 获取指定账号id指定设备类型端的tokenValue 集合 +StpUtil.getLoginDevice(); // 返回当前会话的登录设备类型 +``` + + +### 10、会话管理 +``` java +StpUtil.searchTokenValue(keyword, start, size, sortType); // 根据条件查询Token +StpUtil.searchSessionId(keyword, start, size, sortType); // 根据条件查询SessionId +StpUtil.searchTokenSessionId(keyword, start, size, sortType); // 根据条件查询Token专属Session的Id +``` +详细可参考:[会话治理](/up/search-session) + + +### 11、账号封禁 +``` java +StpUtil.disable(10001, 1200); // 封禁指定账号 +StpUtil.disable(10001); // 指定账号是否已被封禁 (true=已被封禁, false=未被封禁) +StpUtil.getDisableTime(10001); // 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) +StpUtil.untieDisable(loginId); // 解封指定账号 +``` + + +### 12、身份切换 +``` java +StpUtil.switchTo(10044); // 临时切换身份为指定账号id +StpUtil.endSwitch(); // 结束临时切换身份 +StpUtil.isSwitch(); // 当前是否正处于[身份临时切换]中 +StpUtil.switchTo(10044, () -> {}); // 在一个代码段里方法内,临时切换身份为指定账号id +``` + + +### 13、二级认证 +``` java +StpUtil.openSafe(safeTime); // 在当前会话 开启二级认证 +StpUtil.isSafe(); // 当前会话 是否处于二级认证时间内 +StpUtil.checkSafe(); // 检查当前会话是否已通过二级认证,如未通过则抛出异常 +StpUtil.getSafeTime(); // 获取当前会话的二级认证剩余有效时间 (单位: 秒, 返回-2代表尚未通过二级认证) +StpUtil.closeSafe(); // 在当前会话 结束二级认证 +``` + diff --git a/sa-token-doc/doc/more/common-action.md b/sa-token-doc/doc/more/common-action.md index c1397499..c4b6da58 100644 --- a/sa-token-doc/doc/more/common-action.md +++ b/sa-token-doc/doc/more/common-action.md @@ -1,28 +1,34 @@ -# 常用类、方法 -本篇介绍Sa-Token中一些常用的全局对象、类 +# 全局类、方法 +本篇介绍 Sa-Token 中一些常用的全局对象、类 --- ### SaManager -SaManager 负责管理 Sa-Token 所有运行时对象 +SaManager 负责管理 Sa-Token 所有全局组件。 ``` java -SaManager.getConfig(); // 获取全局配置对象 -SaManager.getSaTokenDao(); // 获取数据持久化对象 -SaManager.getStpInterface(); // 获取权限认证对象 -SaManager.getSaTokenAction(); // 获取框架行为对象 -SaManager.getSaTokenContext(); // 获取上下文处理对象 -SaManager.getSaTokenListener(); // 获取侦听器对象 -SaManager.getSaTemp(); // 获取临时令牌认证模块对象 -SaManager.getStpLogic("type"); // 获取指定账号类型的StpLogic对象 +SaManager.getConfig(); // 获取全局配置对象 +SaManager.getSaTokenDao(); // 获取数据持久化对象 +SaManager.getStpInterface(); // 获取权限认证对象 +SaManager.getSaTokenContext(); // 获取一级Context处理对象 +SaManager.getSaTokenSecondContext(); // 获取二级Context处理对象 +SaManager.getSaTokenContextOrSecond(); // 获取一个可用的 Context 处理对象 +SaManager.getSaTokenListener(); // 获取侦听器对象 +SaManager.getSaTemp(); // 获取临时令牌认证模块对象 +SaManager.getSaJsonTemplate(); // 获取 JSON 转换器 Bean +SaManager.getSaSignTemplate(); // 获取参数签名 Bean +SaManager.getStpLogic("type"); // 获取指定账号类型的StpLogic对象 +SaManager.putStpLogic(stpLogic); // 向全局集合中 put 一个 StpLogic ``` ### SaHolder Sa-Token上下文持有类,通过此类快速获取当前环境的相关对象 ``` java +SaHolder.getContext(); // 获取当前请求的 SaTokenContext SaHolder.getRequest(); // 获取当前请求的 [Request] 对象 SaHolder.getResponse(); // 获取当前请求的 [Response] 对象 -SaHolder.getStorage(); // 获取当前请求的 [存储器] 对象 +SaHolder.getStorage(); // 获取当前请求的 [Storage] 对象 +SaHolder.getApplication(); // 获取全局 SaApplication 对象 ``` @@ -36,14 +42,34 @@ Sa-Token内部工具类,包含一些工具方法 SaFoxUtil.printSaToken(); // 打印 Sa-Token 版本字符画 SaFoxUtil.getRandomString(8); // 生成指定长度的随机字符串 SaFoxUtil.isEmpty(str); // 指定字符串是否为null或者空字符串 +SaFoxUtil.isNotEmpty(str); // 指定字符串是否不是null或者空字符串 +SaFoxUtil.equals(a, b); // 比较两个对象是否相等 +SaFoxUtil.equals(a, b); // 比较两个对象是否相等 SaFoxUtil.getMarking28(); // 以当前时间戳和随机int数字拼接一个随机字符串 SaFoxUtil.formatDate(date); // 将日期格式化为yyyy-MM-dd HH:mm:ss字符串 -SaFoxUtil.searchList(); // 从集合里查询数据 +SaFoxUtil.searchList(dataList, prefix, keyword, start, size, sortType); // 从集合里查询数据 +SaFoxUtil.searchList(dataList, start, size, sortType); // 从集合里查询数据 SaFoxUtil.vagueMatch(patt, str); // 字符串模糊匹配 +SaFoxUtil.getValueByType(obj, cs); // 将指定值转化为指定类型 +SaFoxUtil.joinParam(url, parameStr); // 在url上拼接上kv参数并返回 +SaFoxUtil.joinParam(url, key, value); // 在url上拼接上kv参数并返回 +SaFoxUtil.joinSharpParam(url, parameStr); // 在url上拼接锚参数 +SaFoxUtil.joinSharpParam(url, key, value); // 在url上拼接锚参数 +SaFoxUtil.arrayJoin(arr); // 将数组的所有元素使用逗号拼接在一起 +SaFoxUtil.isUrl(str); // 使用正则表达式判断一个字符串是否为URL +SaFoxUtil.encodeUrl(str); // URL编码 +SaFoxUtil.decoderUrl(str); // URL解码 +SaFoxUtil.convertStringToList(str); // 将指定字符串按照逗号分隔符转化为字符串集合 +SaFoxUtil.convertListToString(list); // 将指定集合按照逗号连接成一个字符串 +SaFoxUtil.convertStringToArray(str); // String 转 Array,按照逗号切割 +SaFoxUtil.convertArrayToString(arr); // Array 转 String,按照逗号切割 +SaFoxUtil.emptyList(); // 返回一个空集合 +SaFoxUtil.toList(... strs); // String 数组转集合 ``` + ### SaTokenConfigFactory -配置对象工厂类,通过此类你可以方便的根据properties配置文件创建一个配置对象 +配置对象工厂类,通过此类你可以方便的根据 properties 配置文件创建一个配置对象 1、首先在项目根目录,创建一个配置文件:`sa-token.properties` @@ -80,6 +106,7 @@ SpringMVC操作的工具类,位于包:`sa-token-spring-boot-starter` ``` java SpringMVCUtil.getRequest(); // 获取本次请求的 request 对象 SpringMVCUtil.getResponse(); // 获取本次请求的 response 对象 +SpringMVCUtil.isWeb(); // 判断当前是否处于 Web 上下文中 ``` From 4fac700ff095ea58db651d1a5ee723a3fd78c4b8 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 19 Aug 2022 07:55:35 +0800 Subject: [PATCH 104/144] =?UTF-8?q?SaStorage=20=E8=A7=84=E8=8C=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=AF=BB=E5=86=99=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/application/SaApplication.java | 8 ++-- .../satoken/context/model/SaStorage.java | 39 +++++++++---------- .../cn/dev33/satoken/session/SaSession.java | 3 +- .../dubbo/model/SaStorageForDubbo.java | 6 ++- .../reactor/model/SaStorageForReactor.java | 6 ++- .../servlet/model/SaStorageForServlet.java | 6 ++- .../solon/model/SaStorageForSolon.java | 6 ++- 7 files changed, 39 insertions(+), 35 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java index 324ead9e..f4b6b021 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/application/SaApplication.java @@ -8,6 +8,7 @@ import cn.dev33.satoken.dao.SaTokenDao; /** * Application Model,全局作用域的读取值对象 + *

在应用全局范围内: 存值、取值 * * @author kong * @since: 2022-8-17 @@ -33,11 +34,8 @@ public class SaApplication implements SaSetValueInterface { return set(key, value, SaTokenDao.NEVER_EXPIRE); } - /** - * 删值 - * @param key 要删除的key - * @return 对象自身 - */ + /** 删值 */ + @Override public SaApplication delete(String key) { SaManager.getSaTokenDao().deleteObject(splicingDataKey(key)); return this; diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaStorage.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaStorage.java index 630d18f3..b64aa2f3 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaStorage.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaStorage.java @@ -1,37 +1,34 @@ package cn.dev33.satoken.context.model; +import cn.dev33.satoken.application.SaSetValueInterface; + /** - * [存储器] 包装类 - *

在 Request作用域里: 存值、取值 + * Storage Model,请求作用域的读取值对象 + *

在一次请求范围内: 存值、取值 + * * @author kong * */ -public interface SaStorage { +public interface SaStorage extends SaSetValueInterface { /** * 获取底层源对象 * @return see note */ public Object getSource(); - - /** - * 在 [Request作用域] 里写入一个值 - * @param key 键 - * @param value 值 - */ - public void set(String key, Object value); - - /** - * 在 [Request作用域] 里获取一个值 - * @param key 键 - * @return 值 - */ + + // ---- 实现接口存取值方法 + + /** 取值 */ + @Override public Object get(String key); - /** - * 在 [Request作用域] 里删除一个值 - * @param key 键 - */ - public void delete(String key); + /** 写值 */ + @Override + public SaStorage set(String key, Object value); + + /** 删值 */ + @Override + public SaStorage delete(String key); } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index 06375388..83242afa 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -14,7 +14,8 @@ import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.util.SaFoxUtil; /** - * Session Model + * Session Model,会话作用域的读取值对象 + *

在一次会话范围内: 存值、取值 * * @author kong * diff --git a/sa-token-plugin/sa-token-context-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/model/SaStorageForDubbo.java b/sa-token-plugin/sa-token-context-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/model/SaStorageForDubbo.java index 6311d7ed..b853e7a0 100644 --- a/sa-token-plugin/sa-token-context-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/model/SaStorageForDubbo.java +++ b/sa-token-plugin/sa-token-context-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/model/SaStorageForDubbo.java @@ -37,12 +37,13 @@ public class SaStorageForDubbo implements SaStorage { * 在 [Request作用域] 里写入一个值 */ @Override - public void set(String key, Object value) { + public SaStorageForDubbo set(String key, Object value) { rpcContext.setObjectAttachment(key, value); // 如果是token写入,则回传到Consumer端 if(key.equals(SaTokenConsts.JUST_CREATED_NOT_PREFIX)) { RpcContext.getServerContext().setAttachment(key, value); } + return this; } /** @@ -57,8 +58,9 @@ public class SaStorageForDubbo implements SaStorage { * 在 [Request作用域] 里删除一个值 */ @Override - public void delete(String key) { + public SaStorageForDubbo delete(String key) { rpcContext.removeAttachment(key); + return this; } } diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaStorageForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaStorageForReactor.java index 852b8073..5cfc080a 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaStorageForReactor.java +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaStorageForReactor.java @@ -36,8 +36,9 @@ public class SaStorageForReactor implements SaStorage { * 在 [Request作用域] 里写入一个值 */ @Override - public void set(String key, Object value) { + public SaStorageForReactor set(String key, Object value) { exchange.getAttributes().put(key, value); + return this; } /** @@ -52,8 +53,9 @@ public class SaStorageForReactor implements SaStorage { * 在 [Request作用域] 里删除一个值 */ @Override - public void delete(String key) { + public SaStorageForReactor delete(String key) { exchange.getAttributes().remove(key); + return this; } } diff --git a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaStorageForServlet.java b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaStorageForServlet.java index f7d81491..bd10b8cd 100644 --- a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaStorageForServlet.java +++ b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaStorageForServlet.java @@ -36,8 +36,9 @@ public class SaStorageForServlet implements SaStorage { * 在 [Request作用域] 里写入一个值 */ @Override - public void set(String key, Object value) { + public SaStorageForServlet set(String key, Object value) { request.setAttribute(key, value); + return this; } /** @@ -52,8 +53,9 @@ public class SaStorageForServlet implements SaStorage { * 在 [Request作用域] 里删除一个值 */ @Override - public void delete(String key) { + public SaStorageForServlet delete(String key) { request.removeAttribute(key); + return this; } } diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaStorageForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaStorageForSolon.java index ee60ebe9..6bea71ba 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaStorageForSolon.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaStorageForSolon.java @@ -21,8 +21,9 @@ public class SaStorageForSolon implements SaStorage { } @Override - public void set(String key, Object value) { + public SaStorageForSolon set(String key, Object value) { ctx.attrSet(key, value); + return this; } @Override @@ -31,7 +32,8 @@ public class SaStorageForSolon implements SaStorage { } @Override - public void delete(String key) { + public SaStorageForSolon delete(String key) { ctx.attrMap().remove(key); + return this; } } From ab0776ecc1dbd5c99c9b0114b4c413437971f2c9 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 19 Aug 2022 08:56:51 +0800 Subject: [PATCH 105/144] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E7=9A=84=E4=B8=89=E5=A4=A7=E4=BD=9C=E7=94=A8?= =?UTF-8?q?=E5=9F=9F=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/_sidebar.md | 1 + sa-token-doc/doc/fun/three-scope.md | 42 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 sa-token-doc/doc/fun/three-scope.md diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index c0e35b0e..2a2121c9 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -93,6 +93,7 @@ - [未登录场景值详解](/fun/not-login-scene) - [Token有效期详解](/fun/token-timeout) - [Session模型详解](/fun/session-model) + - [数据读写三大作用域](/fun/three-scope) - [TokenInfo参数详解](/fun/token-info) - [异常细分状态码](/fun/exception-code) - [解决反向代理 uri 丢失的问题](/fun/curr-domain) diff --git a/sa-token-doc/doc/fun/three-scope.md b/sa-token-doc/doc/fun/three-scope.md new file mode 100644 index 00000000..6b4ebe8d --- /dev/null +++ b/sa-token-doc/doc/fun/three-scope.md @@ -0,0 +1,42 @@ +# 三大作用域 + +--- + +Sa-Token 数据存储有三大作用域,分别是: +- `SaStorage` - 请求作用域:存储的数据只在一次请求内有效。 +- `SaSession` - 会话作用域:存储的数据在一次会话范围内有效。 +- `SaApplication` - 全局作用域:存储的数据在全局范围内有效。 + + +### SaStorage - 数据读写三大作用域 +在 SaStorage 中存储的数据只在一次请求范围内有效,请求结束后数据自动清除。使用 SaStorage 时无需处于登录状态。 + +``` java +SaStorage storage = SaHolder.getStorage(); +storage.get("key"); // 取值 +storage.set("key", "value"); // 写值 +storage.delete("key"); // 删值 +``` + + +### SaSession - 会话作用域 +在 SaSession 存储的数据在一次会话范围内有效,会话结束后数据自动清除。必须登录后才能使用 SaSession 对象。 + +``` java +SaSession session = StpUtil.getSession(); +session.get("key"); // 取值 +session.set("key", "value"); // 写值 +session.delete("key"); // 删值 +``` + + +### SaApplication - 全局作用域 +在 SaApplication 存储的数据在全局范围内有效,应用关闭后数据自动清除(如果集成了 Redis 那则是 Redis 关闭后数据自动清除)。使用 SaApplication 时无需处于登录状态。 + +``` java +SaApplication application = SaHolder.getApplication(); +application.get("key"); // 取值 +application.set("key", "value"); // 写值 +application.delete("key"); // 删值 +``` + From ce5b46f9a1022e69683957f96f3e1ad12e0a9f62 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 02:44:01 +0800 Subject: [PATCH 106/144] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BE=A6=E5=90=AC?= =?UTF-8?q?=E5=99=A8=E6=A8=A1=E5=9D=97=E6=94=B9=E4=B8=BA=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E8=AE=A2=E9=98=85=E5=8F=91=E5=B8=83=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/dev33/satoken/SaManager.java | 20 -- .../satoken/listener/SaTokenEventRelease.java | 218 ++++++++++++++++++ ...va => SaTokenListenerForConsolePrint.java} | 4 +- .../listener/SaTokenListenerForSimple.java | 55 +++++ .../cn/dev33/satoken/session/SaSession.java | 9 +- .../java/cn/dev33/satoken/stp/StpLogic.java | 41 ++-- .../satoken/jwt/StpLogicJwtForStateless.java | 6 +- .../satoken/reactor/spring/SaBeanInject.java | 9 +- .../cn/dev33/satoken/solon/XPluginImp.java | 6 +- .../cn/dev33/satoken/spring/SaBeanInject.java | 9 +- 10 files changed, 322 insertions(+), 55 deletions(-) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventRelease.java rename sa-token-core/src/main/java/cn/dev33/satoken/listener/{SaTokenListenerDefaultImpl.java => SaTokenListenerForConsolePrint.java} (94%) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java index 90bf2248..1185a889 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java @@ -13,8 +13,6 @@ import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.json.SaJsonTemplate; import cn.dev33.satoken.json.SaJsonTemplateDefaultImpl; -import cn.dev33.satoken.listener.SaTokenListener; -import cn.dev33.satoken.listener.SaTokenListenerDefaultImpl; import cn.dev33.satoken.sign.SaSignTemplate; import cn.dev33.satoken.sign.SaSignTemplateDefaultImpl; import cn.dev33.satoken.stp.StpInterface; @@ -140,24 +138,6 @@ public class SaManager { return SaTokenContextDefaultImpl.defaultContext; } - /** - * 侦听器 Bean - */ - private volatile static SaTokenListener saTokenListener; - public static void setSaTokenListener(SaTokenListener saTokenListener) { - SaManager.saTokenListener = saTokenListener; - } - public static SaTokenListener getSaTokenListener() { - if (saTokenListener == null) { - synchronized (SaManager.class) { - if (saTokenListener == null) { - setSaTokenListener(new SaTokenListenerDefaultImpl()); - } - } - } - return saTokenListener; - } - /** * 临时令牌验证模块 Bean */ diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventRelease.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventRelease.java new file mode 100644 index 00000000..e0442d52 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventRelease.java @@ -0,0 +1,218 @@ +package cn.dev33.satoken.listener; + +import java.util.ArrayList; +import java.util.List; + +import cn.dev33.satoken.exception.SaTokenException; +import cn.dev33.satoken.stp.SaLoginModel; + +/** + * Sa-Token 事件发布器 + * + * @author kong + * @since: 2022-8-19 + */ +public class SaTokenEventRelease { + + // --------- 注册侦听器 + + private static List listenerList = new ArrayList<>(); + + static { + // 默认添加控制台日志侦听器 + listenerList.add(new SaTokenListenerForConsolePrint()); + } + + /** + * 获取已注册的所有侦听器 + * @return / + */ + public static List getListenerList() { + return listenerList; + } + + /** + * 重置侦听器集合 + * @param listenerList / + */ + public static void setListenerList(List listenerList) { + if(listenerList == null) { + throw new SaTokenException("重置的侦听器集合不可以为空"); + } + SaTokenEventRelease.listenerList = listenerList; + } + + /** + * 注册一个侦听器 + * @param listener / + */ + public static void registerListener(SaTokenListener listener) { + if(listener == null) { + throw new SaTokenException("注册的侦听器不可以为空"); + } + listenerList.add(listener); + } + + /** + * 注册一组侦听器 + * @param listenerList / + */ + public static void registerListenerList(List listenerList) { + if(listenerList == null) { + throw new SaTokenException("注册的侦听器不可以为空"); + } + for (SaTokenListener listener : listenerList) { + if(listener == null) { + throw new SaTokenException("注册的侦听器不可以为空"); + } + } + SaTokenEventRelease.listenerList.addAll(listenerList); + } + + /** + * 移除一个侦听器 + * @param listener / + */ + public static void removeListener(SaTokenListener listener) { + listenerList.remove(listener); + } + + /** + * 移除指定类型的所有侦听器 + * @param cls / + */ + public static void removeListener(Class cls) { + ArrayList listenerListCopy = new ArrayList<>(listenerList); + for (SaTokenListener listener : listenerListCopy) { + if(cls.isAssignableFrom(listener.getClass())) { + listenerList.remove(listener); + } + } + } + + /** + * 清空所有已注册的侦听器 + */ + public static void clearListener() { + listenerList.clear(); + } + + /** + * 判断是否已经注册了指定侦听器 + * @param listener / + * @return / + */ + public static boolean hasListener(SaTokenListener listener) { + return listenerList.contains(listener); + } + + /** + * 判断是否已经注册了指定类型的侦听器 + * @param cls / + * @return / + */ + public static boolean hasListener(Class cls) { + for (SaTokenListener listener : listenerList) { + if(cls.isAssignableFrom(listener.getClass())) { + return true; + } + } + return false; + } + + + // --------- 事件发布 + + /** + * 每次登录时触发 + * @param loginType 账号类别 + * @param loginId 账号id + * @param tokenValue 本次登录产生的 token 值 + * @param loginModel 登录参数 + */ + public static void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { + for (SaTokenListener listener : listenerList) { + listener.doLogin(loginType, loginId, tokenValue, loginModel); + } + } + + /** + * 每次注销时触发 + * @param loginType 账号类别 + * @param loginId 账号id + * @param tokenValue token值 + */ + public static void doLogout(String loginType, Object loginId, String tokenValue) { + for (SaTokenListener listener : listenerList) { + listener.doLogout(loginType, loginId, tokenValue); + } + } + + /** + * 每次被踢下线时触发 + * @param loginType 账号类别 + * @param loginId 账号id + * @param tokenValue token值 + */ + public static void doKickout(String loginType, Object loginId, String tokenValue) { + for (SaTokenListener listener : listenerList) { + listener.doKickout(loginType, loginId, tokenValue); + } + } + + /** + * 每次被顶下线时触发 + * @param loginType 账号类别 + * @param loginId 账号id + * @param tokenValue token值 + */ + public static void doReplaced(String loginType, Object loginId, String tokenValue) { + for (SaTokenListener listener : listenerList) { + listener.doReplaced(loginType, loginId, tokenValue); + } + } + + /** + * 每次被封禁时触发 + * @param loginType 账号类别 + * @param loginId 账号id + * @param disableTime 封禁时长,单位: 秒 + */ + public static void doDisable(String loginType, Object loginId, long disableTime) { + for (SaTokenListener listener : listenerList) { + listener.doDisable(loginType, loginId, disableTime); + } + } + + /** + * 每次被解封时触发 + * @param loginType 账号类别 + * @param loginId 账号id + */ + public static void doUntieDisable(String loginType, Object loginId) { + for (SaTokenListener listener : listenerList) { + listener.doUntieDisable(loginType, loginId); + } + } + + /** + * 每次创建Session时触发 + * @param id SessionId + */ + public static void doCreateSession(String id) { + for (SaTokenListener listener : listenerList) { + listener.doCreateSession(id); + } + } + + /** + * 每次注销Session时触发 + * @param id SessionId + */ + public static void doLogoutSession(String id) { + for (SaTokenListener listener : listenerList) { + listener.doLogoutSession(id); + } + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerDefaultImpl.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java similarity index 94% rename from sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerDefaultImpl.java rename to sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java index d895b658..c13229c2 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerDefaultImpl.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java @@ -7,11 +7,11 @@ import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.util.SaFoxUtil; /** - * Sa-Token 侦听器的默认实现:log打印 + * Sa-Token 侦听器实现:控制台 log 打印 * @author kong * */ -public class SaTokenListenerDefaultImpl implements SaTokenListener { +public class SaTokenListenerForConsolePrint implements SaTokenListener { /** * 每次登录时触发 diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java new file mode 100644 index 00000000..3ad3b7a6 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java @@ -0,0 +1,55 @@ +package cn.dev33.satoken.listener; + +import cn.dev33.satoken.stp.SaLoginModel; + +/** + * Sa-Token 侦听器,默认空实现 + * + *

对所有事件方法提供空实现,方便开发者通过继承此类快速实现一个可用的侦听器 + * + * @author kong + * @since: 2022-8-20 + */ +public class SaTokenListenerForSimple implements SaTokenListener { + + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { + + } + + @Override + public void doLogout(String loginType, Object loginId, String tokenValue) { + + } + + @Override + public void doKickout(String loginType, Object loginId, String tokenValue) { + + } + + @Override + public void doReplaced(String loginType, Object loginId, String tokenValue) { + + } + + @Override + public void doDisable(String loginType, Object loginId, long disableTime) { + + } + + @Override + public void doUntieDisable(String loginType, Object loginId) { + + } + + @Override + public void doCreateSession(String id) { + + } + + @Override + public void doLogoutSession(String id) { + + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index 83242afa..ce6293f5 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -11,6 +11,7 @@ import java.util.concurrent.ConcurrentHashMap; import cn.dev33.satoken.SaManager; import cn.dev33.satoken.application.SaSetValueInterface; import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.listener.SaTokenEventRelease; import cn.dev33.satoken.util.SaFoxUtil; /** @@ -71,8 +72,8 @@ public class SaSession implements SaSetValueInterface, Serializable { public SaSession(String id) { this.id = id; this.createTime = System.currentTimeMillis(); - // $$ 通知监听器 - SaManager.getSaTokenListener().doCreateSession(id); + // $$ 发布事件 + SaTokenEventRelease.doCreateSession(id); } /** @@ -231,8 +232,8 @@ public class SaSession implements SaSetValueInterface, Serializable { /** 注销Session (从持久库删除) */ public void logout() { SaManager.getSaTokenDao().deleteSession(this.id); - // $$ 通知监听器 - SaManager.getSaTokenListener().doLogoutSession(id); + // $$ 发布事件 + SaTokenEventRelease.doLogoutSession(id); } /** 当Session上的tokenSign数量为零时,注销会话 */ diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 4bcf9354..633745ac 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -1,5 +1,10 @@ package cn.dev33.satoken.stp; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import cn.dev33.satoken.SaManager; import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckPermission; @@ -21,17 +26,13 @@ import cn.dev33.satoken.exception.NotRoleException; import cn.dev33.satoken.exception.NotSafeException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.fun.SaFunction; +import cn.dev33.satoken.listener.SaTokenEventRelease; import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.TokenSign; import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaTokenConsts; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - /** * Sa-Token 权限认证,逻辑实现类 * @author kong @@ -362,8 +363,8 @@ public class StpLogic { // 写入 [token-last-activity] setLastActivityToNow(tokenValue); - // $$ 通知监听器,账号xxx 登录成功 - SaManager.getSaTokenListener().doLogin(loginType, id, tokenValue, loginModel); + // $$ 发布事件:账号xxx 登录成功 + SaTokenEventRelease.doLogin(loginType, id, tokenValue, loginModel); // 检查此账号会话数量是否超出最大值 if(config.getMaxLoginCount() != -1) { @@ -427,7 +428,8 @@ public class StpLogic { // 删除Token-Id映射 & 清除Token-Session deleteTokenToIdMapping(tokenValue); deleteTokenSession(tokenValue); - SaManager.getSaTokenListener().doLogout(loginType, loginId, tokenValue); + // $$ 发布事件:指定账号注销 + SaTokenEventRelease.doLogout(loginType, loginId, tokenValue); } // 注销 Session session.logoutByTokenSignCountToZero(); @@ -463,7 +465,8 @@ public class StpLogic { // 删除Token-Id映射 & 清除Token-Session deleteTokenToIdMapping(tokenValue); deleteTokenSession(tokenValue); - SaManager.getSaTokenListener().doLogout(loginType, loginId, tokenValue); + // $$ 发布事件:指定账号注销 + SaTokenEventRelease.doLogout(loginType, loginId, tokenValue); } // 注销 Session session.logoutByTokenSignCountToZero(); @@ -492,8 +495,8 @@ public class StpLogic { return; } - // $$ 通知监听器,某某Token注销下线了 - SaManager.getSaTokenListener().doLogout(loginType, loginId, tokenValue); + // $$ 发布事件:某某Token注销下线了 + SaTokenEventRelease.doLogout(loginType, loginId, tokenValue); // 4. 清理User-Session上的token签名 & 尝试注销User-Session SaSession session = getSessionByLoginId(loginId, false); @@ -530,7 +533,7 @@ public class StpLogic { clearLastActivity(tokenValue); // 将此 token 标记为已被踢下线 updateTokenToIdMapping(tokenValue, NotLoginException.KICK_OUT); - SaManager.getSaTokenListener().doKickout(loginType, loginId, tokenValue); + SaTokenEventRelease.doKickout(loginType, loginId, tokenValue); } // 注销 Session session.logoutByTokenSignCountToZero(); @@ -558,8 +561,8 @@ public class StpLogic { // 3. 给token打上标记:被踢下线 updateTokenToIdMapping(tokenValue, NotLoginException.KICK_OUT); - // $$. 否则通知监听器,某某Token被踢下线了 - SaManager.getSaTokenListener().doKickout(loginType, loginId, tokenValue); + // $$. 发布事件:某某Token被踢下线了 + SaTokenEventRelease.doKickout(loginType, loginId, tokenValue); // 4. 清理User-Session上的token签名 & 尝试注销User-Session SaSession session = getSessionByLoginId(loginId, false); @@ -586,7 +589,7 @@ public class StpLogic { clearLastActivity(tokenValue); // 将此 token 标记为已被顶替 updateTokenToIdMapping(tokenValue, NotLoginException.BE_REPLACED); - SaManager.getSaTokenListener().doReplaced(loginType, loginId, tokenValue); + SaTokenEventRelease.doReplaced(loginType, loginId, tokenValue); } } } @@ -1651,8 +1654,8 @@ public class StpLogic { // 标注为已被封禁 getSaTokenDao().set(splicingKeyDisable(loginId), DisableLoginException.BE_VALUE, disableTime); - // $$ 通知监听器 - SaManager.getSaTokenListener().doDisable(loginType, loginId, disableTime); + // $$ 发布事件 + SaTokenEventRelease.doDisable(loginType, loginId, disableTime); } /** @@ -1680,8 +1683,8 @@ public class StpLogic { public void untieDisable(Object loginId) { getSaTokenDao().delete(splicingKeyDisable(loginId)); - // $$ 通知监听器 - SaManager.getSaTokenListener().doUntieDisable(loginType, loginId); + // $$ 发布事件 + SaTokenEventRelease.doUntieDisable(loginType, loginId); } diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java index 755d1eca..dcc81e68 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java @@ -2,12 +2,12 @@ package cn.dev33.satoken.jwt; import java.util.Map; -import cn.dev33.satoken.SaManager; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.exception.ApiDisabledException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.jwt.exception.SaJwtException; +import cn.dev33.satoken.listener.SaTokenEventRelease; import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpLogic; @@ -98,8 +98,8 @@ public class StpLogicJwtForStateless extends StpLogic { // ------ 2、生成一个token String tokenValue = createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getTimeout(), loginModel.getExtraData()); - // $$ 通知监听器,账号xxx 登录成功 - SaManager.getSaTokenListener().doLogin(loginType, id, tokenValue, loginModel); + // $$ 发布事件:账号xxx 登录成功 + SaTokenEventRelease.doLogin(loginType, id, tokenValue, loginModel); return tokenValue; } diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java index ffd93abf..a4995197 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java @@ -1,5 +1,7 @@ package cn.dev33.satoken.reactor.spring; +import java.util.List; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.util.PathMatcher; @@ -14,6 +16,7 @@ import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.id.SaIdTemplate; import cn.dev33.satoken.id.SaIdUtil; import cn.dev33.satoken.json.SaJsonTemplate; +import cn.dev33.satoken.listener.SaTokenEventRelease; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.sign.SaSignTemplate; import cn.dev33.satoken.stp.StpInterface; @@ -82,11 +85,11 @@ public class SaBeanInject { /** * 注入侦听器Bean * - * @param saTokenListener saTokenListener对象 + * @param listenerList 侦听器集合 */ @Autowired(required = false) - public void setSaTokenListener(SaTokenListener saTokenListener) { - SaManager.setSaTokenListener(saTokenListener); + public void setSaTokenListener(List listenerList) { + SaTokenEventRelease.registerListenerList(listenerList); } /** diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java index 1e7a9786..5bee28d5 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java @@ -14,6 +14,7 @@ import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.id.SaIdTemplate; import cn.dev33.satoken.id.SaIdUtil; import cn.dev33.satoken.json.SaJsonTemplate; +import cn.dev33.satoken.listener.SaTokenEventRelease; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.sign.SaSignTemplate; import cn.dev33.satoken.solon.model.SaContextForSolon; @@ -63,8 +64,10 @@ public class XPluginImp implements Plugin { }); // 注入侦听器 Bean + // TODO:这里需要改为注入一组 Bean context.getWrapAsyn(SaTokenListener.class, bw->{ - SaManager.setSaTokenListener(bw.raw()); +// SaManager.setSaTokenListener(bw.raw()); + SaTokenEventRelease.registerListener(bw.raw()); }); // 注入权限认证 Bean @@ -107,4 +110,5 @@ public class XPluginImp implements Plugin { StpUtil.setStpLogic(bw.raw()); }); } + } \ No newline at end of file diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java index 55529555..cea91671 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java @@ -1,5 +1,7 @@ package cn.dev33.satoken.spring; +import java.util.List; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.util.PathMatcher; @@ -14,6 +16,7 @@ import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.id.SaIdTemplate; import cn.dev33.satoken.id.SaIdUtil; import cn.dev33.satoken.json.SaJsonTemplate; +import cn.dev33.satoken.listener.SaTokenEventRelease; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.sign.SaSignTemplate; import cn.dev33.satoken.stp.StpInterface; @@ -82,11 +85,11 @@ public class SaBeanInject { /** * 注入侦听器Bean * - * @param saTokenListener saTokenListener对象 + * @param listenerList 侦听器集合 */ @Autowired(required = false) - public void setSaTokenListener(SaTokenListener saTokenListener) { - SaManager.setSaTokenListener(saTokenListener); + public void setSaTokenListener(List listenerList) { + SaTokenEventRelease.registerListenerList(listenerList); } /** From 0dd6e1a42983cd349ba81bfff84c0c2ba5fe9394 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 04:25:03 +0800 Subject: [PATCH 107/144] =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=20SaTokenEv?= =?UTF-8?q?entRelease=20->=20SaTokenEventCenter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ntRelease.java => SaTokenEventCenter.java} | 8 ++++---- .../cn/dev33/satoken/session/SaSession.java | 6 +++--- .../java/cn/dev33/satoken/stp/StpLogic.java | 20 +++++++++---------- .../satoken/jwt/StpLogicJwtForStateless.java | 4 ++-- .../satoken/reactor/spring/SaBeanInject.java | 4 ++-- .../cn/dev33/satoken/solon/XPluginImp.java | 4 ++-- .../cn/dev33/satoken/spring/SaBeanInject.java | 4 ++-- 7 files changed, 25 insertions(+), 25 deletions(-) rename sa-token-core/src/main/java/cn/dev33/satoken/listener/{SaTokenEventRelease.java => SaTokenEventCenter.java} (96%) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventRelease.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java similarity index 96% rename from sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventRelease.java rename to sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java index e0442d52..cd708942 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventRelease.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java @@ -7,12 +7,12 @@ import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.stp.SaLoginModel; /** - * Sa-Token 事件发布器 + * Sa-Token 事件中心 事件发布器 * * @author kong * @since: 2022-8-19 */ -public class SaTokenEventRelease { +public class SaTokenEventCenter { // --------- 注册侦听器 @@ -39,7 +39,7 @@ public class SaTokenEventRelease { if(listenerList == null) { throw new SaTokenException("重置的侦听器集合不可以为空"); } - SaTokenEventRelease.listenerList = listenerList; + SaTokenEventCenter.listenerList = listenerList; } /** @@ -66,7 +66,7 @@ public class SaTokenEventRelease { throw new SaTokenException("注册的侦听器不可以为空"); } } - SaTokenEventRelease.listenerList.addAll(listenerList); + SaTokenEventCenter.listenerList.addAll(listenerList); } /** diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java index ce6293f5..9f552f32 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/session/SaSession.java @@ -11,7 +11,7 @@ import java.util.concurrent.ConcurrentHashMap; import cn.dev33.satoken.SaManager; import cn.dev33.satoken.application.SaSetValueInterface; import cn.dev33.satoken.dao.SaTokenDao; -import cn.dev33.satoken.listener.SaTokenEventRelease; +import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.util.SaFoxUtil; /** @@ -73,7 +73,7 @@ public class SaSession implements SaSetValueInterface, Serializable { this.id = id; this.createTime = System.currentTimeMillis(); // $$ 发布事件 - SaTokenEventRelease.doCreateSession(id); + SaTokenEventCenter.doCreateSession(id); } /** @@ -233,7 +233,7 @@ public class SaSession implements SaSetValueInterface, Serializable { public void logout() { SaManager.getSaTokenDao().deleteSession(this.id); // $$ 发布事件 - SaTokenEventRelease.doLogoutSession(id); + SaTokenEventCenter.doLogoutSession(id); } /** 当Session上的tokenSign数量为零时,注销会话 */ diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 633745ac..985dfa55 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -26,7 +26,7 @@ import cn.dev33.satoken.exception.NotRoleException; import cn.dev33.satoken.exception.NotSafeException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.fun.SaFunction; -import cn.dev33.satoken.listener.SaTokenEventRelease; +import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.TokenSign; import cn.dev33.satoken.strategy.SaStrategy; @@ -364,7 +364,7 @@ public class StpLogic { setLastActivityToNow(tokenValue); // $$ 发布事件:账号xxx 登录成功 - SaTokenEventRelease.doLogin(loginType, id, tokenValue, loginModel); + SaTokenEventCenter.doLogin(loginType, id, tokenValue, loginModel); // 检查此账号会话数量是否超出最大值 if(config.getMaxLoginCount() != -1) { @@ -429,7 +429,7 @@ public class StpLogic { deleteTokenToIdMapping(tokenValue); deleteTokenSession(tokenValue); // $$ 发布事件:指定账号注销 - SaTokenEventRelease.doLogout(loginType, loginId, tokenValue); + SaTokenEventCenter.doLogout(loginType, loginId, tokenValue); } // 注销 Session session.logoutByTokenSignCountToZero(); @@ -466,7 +466,7 @@ public class StpLogic { deleteTokenToIdMapping(tokenValue); deleteTokenSession(tokenValue); // $$ 发布事件:指定账号注销 - SaTokenEventRelease.doLogout(loginType, loginId, tokenValue); + SaTokenEventCenter.doLogout(loginType, loginId, tokenValue); } // 注销 Session session.logoutByTokenSignCountToZero(); @@ -496,7 +496,7 @@ public class StpLogic { } // $$ 发布事件:某某Token注销下线了 - SaTokenEventRelease.doLogout(loginType, loginId, tokenValue); + SaTokenEventCenter.doLogout(loginType, loginId, tokenValue); // 4. 清理User-Session上的token签名 & 尝试注销User-Session SaSession session = getSessionByLoginId(loginId, false); @@ -533,7 +533,7 @@ public class StpLogic { clearLastActivity(tokenValue); // 将此 token 标记为已被踢下线 updateTokenToIdMapping(tokenValue, NotLoginException.KICK_OUT); - SaTokenEventRelease.doKickout(loginType, loginId, tokenValue); + SaTokenEventCenter.doKickout(loginType, loginId, tokenValue); } // 注销 Session session.logoutByTokenSignCountToZero(); @@ -562,7 +562,7 @@ public class StpLogic { updateTokenToIdMapping(tokenValue, NotLoginException.KICK_OUT); // $$. 发布事件:某某Token被踢下线了 - SaTokenEventRelease.doKickout(loginType, loginId, tokenValue); + SaTokenEventCenter.doKickout(loginType, loginId, tokenValue); // 4. 清理User-Session上的token签名 & 尝试注销User-Session SaSession session = getSessionByLoginId(loginId, false); @@ -589,7 +589,7 @@ public class StpLogic { clearLastActivity(tokenValue); // 将此 token 标记为已被顶替 updateTokenToIdMapping(tokenValue, NotLoginException.BE_REPLACED); - SaTokenEventRelease.doReplaced(loginType, loginId, tokenValue); + SaTokenEventCenter.doReplaced(loginType, loginId, tokenValue); } } } @@ -1655,7 +1655,7 @@ public class StpLogic { getSaTokenDao().set(splicingKeyDisable(loginId), DisableLoginException.BE_VALUE, disableTime); // $$ 发布事件 - SaTokenEventRelease.doDisable(loginType, loginId, disableTime); + SaTokenEventCenter.doDisable(loginType, loginId, disableTime); } /** @@ -1684,7 +1684,7 @@ public class StpLogic { getSaTokenDao().delete(splicingKeyDisable(loginId)); // $$ 发布事件 - SaTokenEventRelease.doUntieDisable(loginType, loginId); + SaTokenEventCenter.doUntieDisable(loginType, loginId); } diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java index dcc81e68..3653b2d2 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java @@ -7,7 +7,7 @@ import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.exception.ApiDisabledException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.jwt.exception.SaJwtException; -import cn.dev33.satoken.listener.SaTokenEventRelease; +import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpLogic; @@ -99,7 +99,7 @@ public class StpLogicJwtForStateless extends StpLogic { String tokenValue = createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getTimeout(), loginModel.getExtraData()); // $$ 发布事件:账号xxx 登录成功 - SaTokenEventRelease.doLogin(loginType, id, tokenValue, loginModel); + SaTokenEventCenter.doLogin(loginType, id, tokenValue, loginModel); return tokenValue; } diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java index a4995197..14ac0390 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java @@ -16,7 +16,7 @@ import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.id.SaIdTemplate; import cn.dev33.satoken.id.SaIdUtil; import cn.dev33.satoken.json.SaJsonTemplate; -import cn.dev33.satoken.listener.SaTokenEventRelease; +import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.sign.SaSignTemplate; import cn.dev33.satoken.stp.StpInterface; @@ -89,7 +89,7 @@ public class SaBeanInject { */ @Autowired(required = false) public void setSaTokenListener(List listenerList) { - SaTokenEventRelease.registerListenerList(listenerList); + SaTokenEventCenter.registerListenerList(listenerList); } /** diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java index 5bee28d5..c8966040 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java @@ -14,7 +14,7 @@ import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.id.SaIdTemplate; import cn.dev33.satoken.id.SaIdUtil; import cn.dev33.satoken.json.SaJsonTemplate; -import cn.dev33.satoken.listener.SaTokenEventRelease; +import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.sign.SaSignTemplate; import cn.dev33.satoken.solon.model.SaContextForSolon; @@ -67,7 +67,7 @@ public class XPluginImp implements Plugin { // TODO:这里需要改为注入一组 Bean context.getWrapAsyn(SaTokenListener.class, bw->{ // SaManager.setSaTokenListener(bw.raw()); - SaTokenEventRelease.registerListener(bw.raw()); + SaTokenEventCenter.registerListener(bw.raw()); }); // 注入权限认证 Bean diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java index cea91671..c2362bc4 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java @@ -16,7 +16,7 @@ import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.id.SaIdTemplate; import cn.dev33.satoken.id.SaIdUtil; import cn.dev33.satoken.json.SaJsonTemplate; -import cn.dev33.satoken.listener.SaTokenEventRelease; +import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.sign.SaSignTemplate; import cn.dev33.satoken.stp.StpInterface; @@ -89,7 +89,7 @@ public class SaBeanInject { */ @Autowired(required = false) public void setSaTokenListener(List listenerList) { - SaTokenEventRelease.registerListenerList(listenerList); + SaTokenEventCenter.registerListenerList(listenerList); } /** From fd7bc38136ef97df5a4c7d5070392a28ba68b032 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 04:25:20 +0800 Subject: [PATCH 108/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E4=BE=A6=E5=90=AC=E5=99=A8=E7=9A=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/_sidebar.md | 2 +- sa-token-doc/doc/fun/sa-token-context.md | 2 +- sa-token-doc/doc/up/global-listener.md | 151 ++++++++++++++++++++--- 3 files changed, 138 insertions(+), 17 deletions(-) diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 2a2121c9..1823a91f 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -69,6 +69,7 @@ - [和 jwt 集成](/plugin/jwt-extend) - [和 Dubbo 集成](/plugin/dubbo-extend) - [Sa-Token 插件开发指南](/fun/plugin-dev) + - [自定义 SaTokenContext 指南](/fun/sa-token-context) - **API手册** - [StpUtil-鉴权工具类](/api/stp-util) @@ -100,7 +101,6 @@ - [参考:把权限放在缓存里](/fun/jur-cache) - [解决跨域问题](/fun/cors-filter) - [技术选型:SSO 与 OAuth2 对比](/fun/sso-vs-oauth2) - - [自定义 SaTokenContext 指南](/fun/sa-token-context) - [框架源码所有技术栈](/fun/tech-stack) - [issue 提问模板](/fun/issue-template) - [为Sa-Token贡献代码](/fun/git-pr) diff --git a/sa-token-doc/doc/fun/sa-token-context.md b/sa-token-doc/doc/fun/sa-token-context.md index 761650d6..a0dd586c 100644 --- a/sa-token-doc/doc/fun/sa-token-context.md +++ b/sa-token-doc/doc/fun/sa-token-context.md @@ -14,7 +14,7 @@ 解决这个问题的关键就在于 `SaTokenContext` 接口,此接口的作用是屏蔽掉不同 Web 框架之间的差异,提供统一的调用API: -![sa-token-context](https://oss.dev33.cn/sa-token/doc/sa-token-context.png 's-w') +![sa-token-context](https://oss.dev33.cn/sa-token/doc/sa-token-context.svg 's-w') SaTokenContext只是一个接口,没有工作能力,这也就意味着 SaTokenContext 接口的实现是必须的。 diff --git a/sa-token-doc/doc/up/global-listener.md b/sa-token-doc/doc/up/global-listener.md index fc17ce9f..1e202cfd 100644 --- a/sa-token-doc/doc/up/global-listener.md +++ b/sa-token-doc/doc/up/global-listener.md @@ -1,15 +1,26 @@ # 全局侦听器 -接口`SaTokenListener`是Sa-Token的全局侦听器,通过实现此接口,你可以在用户登陆、退出、被踢下线等关键性操作时进行一些AOP操作。 - -框架对此侦听器的默认实现是log日志输出,你可以通过配置`sa-token.is-log=true`开启。 - -下面我们演示一下如何自定义侦听器的实现: - --- +### 1、工作原理 -### 自定义侦听器实现 +Sa-Token 提供一种侦听器机制,通过注册侦听器,你可以订阅框架的一些关键性事件,例如:用户登录、退出、被踢下线等。 + +事件触发流程大致如下: + +![sa-token-listener](https://oss.dev33.cn/sa-token/doc/sa-token-listener.svg 's-w') + +框架默认内置了侦听器 `SaTokenListenerForConsolePrint` 实现:[代码参考](https://gitee.com/dromara/sa-token/blob/master/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java) +,功能是控制台 log 打印输出,你可以通过配置`sa-token.is-log=true`开启。 + +要注册自定义的侦听器也非常简单: +1. 新建类实现 `SaTokenListener` 接口。 +2. 将实现类注册到 `SaTokenEventCenter` 事件发布中心。 + + +### 2、自定义侦听器实现 + +##### 2.1、新建实现类: 新建`MySaTokenListener.java`,继承`SaTokenListener`接口,并添加上注解`@Component`,保证此类被`SpringBoot`扫描到: @@ -23,51 +34,161 @@ public class MySaTokenListener implements SaTokenListener { /** 每次登录时触发 */ @Override public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { - // ... + System.out.println("---------- 自定义侦听器实现 doLogin"); } /** 每次注销时触发 */ @Override public void doLogout(String loginType, Object loginId, String tokenValue) { - // ... + System.out.println("---------- 自定义侦听器实现 doLogout"); } /** 每次被踢下线时触发 */ @Override public void doKickout(String loginType, Object loginId, String tokenValue) { - // ... + System.out.println("---------- 自定义侦听器实现 doKickout"); } /** 每次被顶下线时触发 */ @Override public void doReplaced(String loginType, Object loginId, String tokenValue) { - // ... + System.out.println("---------- 自定义侦听器实现 doReplaced"); } /** 每次被封禁时触发 */ @Override public void doDisable(String loginType, Object loginId, long disableTime) { - // ... + System.out.println("---------- 自定义侦听器实现 doDisable"); } /** 每次被解封时触发 */ @Override public void doUntieDisable(String loginType, Object loginId) { - // ... + System.out.println("---------- 自定义侦听器实现 doUntieDisable"); } /** 每次创建Session时触发 */ @Override public void doCreateSession(String id) { - // ... + System.out.println("---------- 自定义侦听器实现 doCreateSession"); } /** 每次注销Session时触发 */ @Override public void doLogoutSession(String id) { - // ... + System.out.println("---------- 自定义侦听器实现 doLogoutSession"); } } ``` +##### 2.2、将侦听器注册到事件中心: + +以上代码由于添加了 `@Component` 注解,会被 SpringBoot 扫描并自动注册到事件中心,此时我们无需手动注册。 + +如果我们没有添加 `@Component` 注解或者项目属于非 IOC 自动注入环境,则需要我们手动将这个侦听器注册到事件中心: + +``` java +// 将侦听器注册到事件发布中心 +SaTokenEventCenter.registerListener(new MySaTokenListener()); +``` + +事件中心的其它一些常用方法: + +``` java +// 获取已注册的所有侦听器 +SaTokenEventCenter.getListenerList(); + +// 重置侦听器集合 +SaTokenEventCenter.setListenerList(listenerList); + +// 注册一个侦听器 +SaTokenEventCenter.registerListener(listener); + +// 注册一组侦听器 +SaTokenEventCenter.registerListenerList(listenerList); + +// 移除一个侦听器 +SaTokenEventCenter.removeListener(listener); + +// 移除指定类型的所有侦听器 +SaTokenEventCenter.removeListener(cls); + +// 清空所有已注册的侦听器 +SaTokenEventCenter.clearListener(); + +// 判断是否已经注册了指定侦听器 +SaTokenEventCenter.hasListener(listener); + +// 判断是否已经注册了指定类型的侦听器 +SaTokenEventCenter.hasListener(cls); +``` + +##### 2.3、启动测试: +在 `TestController` 中添加登录测试代码: +``` java +// 测试登录接口 +@RequestMapping("login") +public SaResult login() { + System.out.println("登录前"); + StpUtil.login(10001); + System.out.println("登录后"); + return SaResult.ok(); +} +``` + +启动项目,访问登录接口,观察控制台输出: + +![sa-token-listener-println](https://oss.dev33.cn/sa-token/doc/sa-token-listener-println.png 's-w-sh') + + +### 3、其它注意点 + +##### 3.1、你可以通过继承 `SaTokenListenerForSimple` 快速实现一个侦听器: + +``` java +@Component +public class MySaTokenListener implements SaTokenListenerForSimple { + /* + * SaTokenListenerForSimple 对所有事件提供了空实现,通过继承此类,你只需重写一部分方法即可实现一个可用的侦听器。 + */ + /** 每次登录时触发 */ + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { + System.out.println("---------- 自定义侦听器实现 doLogin"); + } +} +``` + +##### 3.2、使用匿名内部类的方式注册: +``` java +// 登录时触发 +SaTokenEventCenter.registerListener(new SaTokenListenerForSimple() { + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { + System.out.println("---------------- doLogin"); + } +}); +``` + +##### 3.3、使用 try-catch 包裹不安全的代码: +如果你认为你的事件处理代码是不安全的(代码可能在运行时抛出异常),你则需要使用 `try-catch` 包裹代码,以防因为抛出异常导致 Sa-Token 的整个登录流程被强制中断。 + +``` java +// 登录时触发 +SaTokenEventCenter.registerListener(new SaTokenListenerForSimple() { + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { + try { + // 不安全代码需要写在 try-catch 里 + // ...... + } catch (Exception e) { + e.printStackTrace(); + } + } +}); +``` + +##### 3.4、疑问:一个项目可以注册多个侦听器吗? +可以,多个侦听器间彼此独立,互不影响,按照注册顺序依次接受到事件通知。 + From 9d32174e60062dc49d23ae2c1cfc139cdb08d3d9 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 08:29:56 +0800 Subject: [PATCH 109/144] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96bean?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=E6=94=B9=E4=B8=BAEventBus=E8=AE=A2=E9=98=85?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/dev33/satoken/solon/XPluginImp.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java index c8966040..f7b5e800 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java @@ -3,9 +3,14 @@ package cn.dev33.satoken.solon; import org.noear.solon.Solon; import org.noear.solon.core.AopContext; import org.noear.solon.core.Plugin; +import org.noear.solon.core.event.EventBus; import cn.dev33.satoken.SaManager; -import cn.dev33.satoken.annotation.*; +import cn.dev33.satoken.annotation.SaCheckBasic; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import cn.dev33.satoken.annotation.SaCheckSafe; import cn.dev33.satoken.basic.SaBasicTemplate; import cn.dev33.satoken.basic.SaBasicUtil; import cn.dev33.satoken.config.SaTokenConfig; @@ -17,8 +22,8 @@ import cn.dev33.satoken.json.SaJsonTemplate; import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.sign.SaSignTemplate; -import cn.dev33.satoken.solon.model.SaContextForSolon; import cn.dev33.satoken.solon.integration.SaTokenAnnotationInterceptor; +import cn.dev33.satoken.solon.model.SaContextForSolon; import cn.dev33.satoken.stp.StpInterface; import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; @@ -64,10 +69,8 @@ public class XPluginImp implements Plugin { }); // 注入侦听器 Bean - // TODO:这里需要改为注入一组 Bean - context.getWrapAsyn(SaTokenListener.class, bw->{ -// SaManager.setSaTokenListener(bw.raw()); - SaTokenEventCenter.registerListener(bw.raw()); + EventBus.subscribe(SaTokenListener.class, bw->{ + SaTokenEventCenter.registerListener(bw); }); // 注入权限认证 Bean From 77860d27e92cc61e6bafa05c6864ddf53ce47bf6 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 08:30:32 +0800 Subject: [PATCH 110/144] =?UTF-8?q?Solon=20=E4=BE=9D=E8=B5=96=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E4=B8=BA=201.10.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-demo/sa-token-demo-solon/pom.xml | 2 +- sa-token-starter/sa-token-solon-plugin/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sa-token-demo/sa-token-demo-solon/pom.xml b/sa-token-demo/sa-token-demo-solon/pom.xml index 0f803e9f..83c70593 100644 --- a/sa-token-demo/sa-token-demo-solon/pom.xml +++ b/sa-token-demo/sa-token-demo-solon/pom.xml @@ -18,7 +18,7 @@ org.noear solon-web - 1.9.2 + 1.10.0 diff --git a/sa-token-starter/sa-token-solon-plugin/pom.xml b/sa-token-starter/sa-token-solon-plugin/pom.xml index 0f44b91d..ad6aa6aa 100644 --- a/sa-token-starter/sa-token-solon-plugin/pom.xml +++ b/sa-token-starter/sa-token-solon-plugin/pom.xml @@ -20,7 +20,7 @@ org.noear solon - 1.9.2 + 1.10.0 From 1eddae5e1e380ca9926f84e6b2e475190a133ba5 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 08:56:32 +0800 Subject: [PATCH 111/144] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=8D=95=E7=82=B9?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=A8=A1=E5=9D=97=20ssoLogoutCall=20?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=A1=B9=E6=97=A0=E6=95=88=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/dev33/satoken/sso/SaSsoHandle.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java index 4ad7ebf9..e59e2e08 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java @@ -361,10 +361,22 @@ public class SaSsoHandle { // --------- 两种模式 if(cfg.getIsHttp()) { - // 模式三:使用 http 请求从认证中心校验ticket + // q1、使用模式三:使用 http 请求从认证中心校验ticket + + // 计算当前 sso-client 的单点注销回调地址 String ssoLogoutCall = null; - if(cfg.getIsSlo() && SaFoxUtil.isNotEmpty(currUri)) { - ssoLogoutCall = SaHolder.getRequest().getUrl().replace(currUri, Api.ssoLogoutCall); + if(cfg.getIsSlo()) { + // 如果配置了回调地址,就使用配置的值: + if(SaFoxUtil.isNotEmpty(cfg.getSsoLogoutCall())) { + ssoLogoutCall = cfg.getSsoLogoutCall(); + } + // 如果提供了当前 uri,则根据此值来计算: + else if(SaFoxUtil.isNotEmpty(currUri)) { + ssoLogoutCall = SaHolder.getRequest().getUrl().replace(currUri, Api.ssoLogoutCall); + } + // 否则视为不注册单点注销回调地址 + else { + } } // 发起请求 @@ -379,7 +391,7 @@ public class SaSsoHandle { throw new SaSsoException(result.getMsg()).setCode(SaSsoExceptionCode.CODE_20005); } } else { - // 模式二:直连Redis校验ticket + // q2、使用模式二:直连Redis校验ticket return SaSsoUtil.checkTicket(ticket); } } From bd4247554e40f9e49842943dc4e08aa1e7044acf Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 09:03:09 +0800 Subject: [PATCH 112/144] =?UTF-8?q?=E5=88=A0=E9=99=A4=20sa-token-jwt=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E8=BF=87=E6=9C=9F=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/dev33/satoken/jwt/StpLogicJwtForMix.java | 12 ------------ .../cn/dev33/satoken/jwt/StpLogicJwtForStyle.java | 12 ------------ 2 files changed, 24 deletions(-) delete mode 100644 sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMix.java delete mode 100644 sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStyle.java diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMix.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMix.java deleted file mode 100644 index 761300b7..00000000 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMix.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.dev33.satoken.jwt; - -/** - * 已更名为 StpLogicJwtForMixin,请更换 - * - * @author kong - * @since: 2022-5-1 - */ -@Deprecated -public class StpLogicJwtForMix extends StpLogicJwtForMixin { - -} diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStyle.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStyle.java deleted file mode 100644 index ba057fcb..00000000 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStyle.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.dev33.satoken.jwt; - -/** - * 已更名为 StpLogicJwtForSimple,请更换 - * - * @author kong - * @since: 2022-5-1 - */ -@Deprecated -public class StpLogicJwtForStyle extends StpLogicJwtForSimple { - -} From a6f949aee1c39de70fd6b244ab1ec51348340023 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 09:59:19 +0800 Subject: [PATCH 113/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- sa-token-doc/doc/README.md | 2 +- sa-token-doc/doc/fun/sa-token-context.md | 2 +- sa-token-doc/doc/oauth2/readme.md | 6 ++---- sa-token-doc/index.html | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 218052da..6f9c1dcc 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ - **分布式会话** —— 提供jwt集成、共享数据中心两种分布式会话方案 - **微服务网关鉴权** —— 适配Gateway、ShenYu、Zuul等常见网关的路由拦截认证 - **单点登录** —— 内置三种单点登录模式:无论是否跨域、是否共享Redis,都可以搞定 -- **OAuth2.0认证** —— 基于RFC-6749标准编写,OAuth2.0标准流程的授权认证,支持openid模式 +- **OAuth2.0认证** —— 轻松搭建 OAuth2.0 服务,支持openid模式 - **二级认证** —— 在已登录的基础上再次认证,保证安全性 - **Basic认证** —— 一行代码接入 Http Basic 认证 - **独立Redis** —— 将权限缓存与业务缓存分离 diff --git a/sa-token-doc/doc/README.md b/sa-token-doc/doc/README.md index d4a702c5..7022c5bd 100644 --- a/sa-token-doc/doc/README.md +++ b/sa-token-doc/doc/README.md @@ -96,7 +96,7 @@ StpUtil.switchTo(10044); // 将当前会话身份临时切换为其它账号 - **分布式会话** —— 提供jwt集成、共享数据中心两种分布式会话方案 - **微服务网关鉴权** —— 适配Gateway、ShenYu、Zuul等常见网关的路由拦截认证 - **单点登录** —— 内置三种单点登录模式:无论是否跨域、是否共享Redis,都可以搞定 -- **OAuth2.0认证** —— 基于RFC-6749标准编写,OAuth2.0标准流程的授权认证,支持openid模式 +- **OAuth2.0认证** —— 轻松搭建 OAuth2.0 服务,支持openid模式 - **二级认证** —— 在已登录的基础上再次认证,保证安全性 - **Basic认证** —— 一行代码接入 Http Basic 认证 - **独立Redis** —— 将权限缓存与业务缓存分离 diff --git a/sa-token-doc/doc/fun/sa-token-context.md b/sa-token-doc/doc/fun/sa-token-context.md index a0dd586c..1bcf707b 100644 --- a/sa-token-doc/doc/fun/sa-token-context.md +++ b/sa-token-doc/doc/fun/sa-token-context.md @@ -14,7 +14,7 @@ 解决这个问题的关键就在于 `SaTokenContext` 接口,此接口的作用是屏蔽掉不同 Web 框架之间的差异,提供统一的调用API: -![sa-token-context](https://oss.dev33.cn/sa-token/doc/sa-token-context.svg 's-w') +![sa-token-context](https://oss.dev33.cn/sa-token/doc/sa-token-context.svg 's-w') SaTokenContext只是一个接口,没有工作能力,这也就意味着 SaTokenContext 接口的实现是必须的。 diff --git a/sa-token-doc/doc/oauth2/readme.md b/sa-token-doc/doc/oauth2/readme.md index fd9c51d0..59d9e4b0 100644 --- a/sa-token-doc/doc/oauth2/readme.md +++ b/sa-token-doc/doc/oauth2/readme.md @@ -11,15 +11,13 @@ [OAuth2.0 简单解释](https://www.ruanyifeng.com/blog/2019/04/oauth_design.html) - - 如果你还不知道你的项目应该选择 SSO 还是 OAuth2.0,可以参考这篇:[技术选型:[ 单点登录 ] VS [ OAuth2.0 ]](/fun/sso-vs-oauth2) ### OAuth2.0 四种模式 -Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) 编写,基于不同的使用场景,OAuth2.0设计了四种模式: +基于不同的使用场景,OAuth2.0设计了四种模式: 1. 授权码(Authorization Code):OAuth2.0标准授权步骤,Server端向Client端下放Code码,Client端再用Code码换取授权Token 2. 隐藏式(Implicit):无法使用授权码模式时的备用选择,Server端使用URL重定向方式直接将Token下放到Client端页面 @@ -28,7 +26,7 @@ Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) ![https://oss.dev33.cn/sa-token/doc/oauth2/sa-oauth2-setup.png](https://oss.dev33.cn/sa-token/doc/oauth2/sa-oauth2-setup.png) -接下来我们将通过简单示例演示如何在Sa-OAuth2中完成这四种模式的对接: [搭建OAuth2-Server](/oauth2/oauth2-server) +接下来我们将通过简单示例演示如何在 Sa-OAuth2 中完成这四种模式的对接: [搭建OAuth2-Server](/oauth2/oauth2-server) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 2f3fea21..243a5e58 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -123,7 +123,7 @@

🍂 OAuth2.0

-

基于 RFC-6749 标准编写,轻松搭建 OAuth2.0 认证中心,支持四种授权模式,支持openid机制

+

轻松搭建 OAuth2.0 认证中心,支持四种授权模式,支持 openid 授权机制,支持二次扩展开发

💦️ 微服务支持

From c26bb73af175e72bc85c4c4840fbab411b002f62 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 12:05:36 +0800 Subject: [PATCH 114/144] =?UTF-8?q?=E5=AE=8C=E5=96=84SSO=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sso-login.html | 4 +- .../sa-token-demo-sso-server-h5/login.js | 2 +- .../src/main/java/com/pj/h5/H5Controller.java | 2 +- .../src/main/resources/application.yml | 2 +- .../src/main/java/com/pj/h5/H5Controller.java | 6 +- sa-token-doc/doc/sso/sso-apidoc.md | 81 ++++++++++++++++++- sa-token-doc/doc/sso/sso-h5.md | 6 +- sa-token-doc/doc/sso/sso-type1.md | 4 +- 8 files changed, 93 insertions(+), 14 deletions(-) diff --git a/sa-token-demo/sa-token-demo-sso-client-h5/sso-login.html b/sa-token-demo/sa-token-demo-sso-client-h5/sso-login.html index 4191fe89..3b18cdd3 100644 --- a/sa-token-demo/sa-token-demo-sso-client-h5/sso-login.html +++ b/sa-token-demo/sa-token-demo-sso-client-h5/sso-login.html @@ -30,7 +30,7 @@ // 重定向至认证中心 function goSsoAuthUrl() { - sa.ajax('/getSsoAuthUrl', {clientLoginUrl: location.href}, function(res) { + sa.ajax('/sso/getSsoAuthUrl', {clientLoginUrl: location.href}, function(res) { console.log(res); location.href = res.data; }) @@ -38,7 +38,7 @@ // 根据ticket值登录 function doLoginByTicket(ticket) { - sa.ajax('/doLoginByTicket', {ticket: ticket}, function(res) { + sa.ajax('/sso/doLoginByTicket', {ticket: ticket}, function(res) { console.log(res); if(res.code == 200) { localStorage.setItem('satoken', res.data); diff --git a/sa-token-demo/sa-token-demo-sso-server-h5/login.js b/sa-token-demo/sa-token-demo-sso-server-h5/login.js index 7738b43c..0b87ab7c 100644 --- a/sa-token-demo/sa-token-demo-sso-server-h5/login.js +++ b/sa-token-demo/sa-token-demo-sso-server-h5/login.js @@ -42,7 +42,7 @@ sa.ajax = function(url, data, successFn) { // ----------------------------------- 相关事件 ----------------------------------- // 检查当前是否已经登录,如果已登录则直接开始跳转,如果未登录则等待用户输入账号密码 -sa.ajax("/getRedirectUrl", {redirect: getParam('redirect', ''), mode: getParam('mode', '')}, function(res) { +sa.ajax("/sso/getRedirectUrl", {redirect: getParam('redirect', ''), mode: getParam('mode', '')}, function(res) { if(res.code == 200) { // 已登录,并且redirect地址有效,开始跳转 location.href = decodeURIComponent(res.data); diff --git a/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/h5/H5Controller.java b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/h5/H5Controller.java index a7440292..0641b0b2 100644 --- a/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/h5/H5Controller.java +++ b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/h5/H5Controller.java @@ -22,7 +22,7 @@ public class H5Controller { /** * 获取 redirectUrl */ - @RequestMapping("/getRedirectUrl") + @RequestMapping("/sso/getRedirectUrl") private Object getRedirectUrl(String redirect, String mode) { // 未登录情况下,返回 code=401 if(StpUtil.isLogin() == false) { diff --git a/sa-token-demo/sa-token-demo-sso-server/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso-server/src/main/resources/application.yml index 2dc74bab..babc1766 100644 --- a/sa-token-demo/sa-token-demo-sso-server/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-sso-server/src/main/resources/application.yml @@ -5,7 +5,7 @@ server: # Sa-Token 配置 sa-token: # -------------- SSO-模式一相关配置 (非模式一不需要配置) - # cookie: + # cookie: # 配置Cookie作用域 # domain: stp.com diff --git a/sa-token-demo/sa-token-demo-sso2-client/src/main/java/com/pj/h5/H5Controller.java b/sa-token-demo/sa-token-demo-sso2-client/src/main/java/com/pj/h5/H5Controller.java index de1a350c..03448242 100644 --- a/sa-token-demo/sa-token-demo-sso2-client/src/main/java/com/pj/h5/H5Controller.java +++ b/sa-token-demo/sa-token-demo-sso2-client/src/main/java/com/pj/h5/H5Controller.java @@ -25,16 +25,16 @@ public class H5Controller { } // 返回SSO认证中心登录地址 - @RequestMapping("/getSsoAuthUrl") + @RequestMapping("/sso/getSsoAuthUrl") public SaResult getSsoAuthUrl(String clientLoginUrl) { String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, ""); return SaResult.data(serverAuthUrl); } // 根据ticket进行登录 - @RequestMapping("/doLoginByTicket") + @RequestMapping("/sso/doLoginByTicket") public SaResult doLoginByTicket(String ticket) { - Object loginId = SaSsoHandle.checkTicket(ticket, "/doLoginByTicket"); + Object loginId = SaSsoHandle.checkTicket(ticket, "/sso/doLoginByTicket"); if(loginId != null) { StpUtil.login(loginId); return SaResult.data(StpUtil.getTokenValue()); diff --git a/sa-token-doc/doc/sso/sso-apidoc.md b/sa-token-doc/doc/sso/sso-apidoc.md index d215913c..04248463 100644 --- a/sa-token-doc/doc/sso/sso-apidoc.md +++ b/sa-token-doc/doc/sso/sso-apidoc.md @@ -8,6 +8,9 @@ --- +## 一、SSO-Server 认证中心接口 + + ### 1、单点登录授权地址 ``` url http://{host}:{port}/sso/auth @@ -102,7 +105,7 @@ http://{host}:{port}/sso/logout?back=xxx | loginId | 是 | 要注销的账号 id | | timestamp | 是 | 当前时间戳,13位 | | nonce | 是 | 随机字符串 | -| sign | 是 | 签名,生成算法:`md5( loginId={value}&nonce={value}×tamp={value}&key={secretkey秘钥} )` | +| sign | 是 | 签名,生成算法:`md5( loginId={账号id}&nonce={随机字符串}×tamp={13位时间戳}&key={secretkey秘钥} )` | 例如: ``` url @@ -136,6 +139,82 @@ SSO 认证中心只有这四个接口,接下来让我一起来看一下 Client +--- + +## 二、SSO-Client 应用端开放接口 + +### 1、登录地址 +``` url +http://{host}:{port}/sso/login +``` + +接收参数: + +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| back | 是 | 登录成功后的重定向地址,一般填写 location.href(从哪来回哪去) | +| ticket | 否 | 授权 ticket 码 | + +此接口有两种访问方式: +- 方式一:我们需要登录操作,所以带着 back 参数主动访问此接口,框架会拼接好参数后再次将用户重定向至认证中心。 +- 方式二:用户在认证中心登录成功后,带着 ticket 参数重定向而来,此为框架自动处理的逻辑,开发者无需关心。 + + +### 2、注销地址 +``` url +http://{host}:{port}/sso/logout +``` + +接收参数: + +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| back | 否 | 注销成功后的重定向地址,一般填写 location.href(从哪来回哪去),也可以填写 self 字符串,含义同上 | + +此接口有两种访问方式: +- 方式一:直接 `location.href` 网页跳转,此时可携带 back 参数。 +- 方式二:使用 Ajax 异步调用,注销成功将返回以下内容: + +``` js +{ + "code": 200, // 200表示请求成功,非200标识请求失败 + "msg": "单点注销成功", + "data": null +} +``` + + +### 3、单点注销回调接口 +此接口仅配置模式三 `(isHttp=true)` 时打开,且为框架回调,开发者无需关心 + +``` url +http://{host}:{port}/sso/logoutCall +``` + +接受参数: + +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| loginId | 是 | 要注销的账号 id | +| timestamp | 是 | 当前时间戳,13位 | +| nonce | 是 | 随机字符串 | +| sign | 是 | 签名,生成算法:`md5( loginId={账号id}&nonce={随机字符串}×tamp={13位时间戳}&key={secretkey秘钥} )` | + +返回数据: + +``` js +{ + "code": 200, // 200表示请求成功,非200标识请求失败 + "msg": "单点注销回调成功", + "data": null +} +``` + + + + + + diff --git a/sa-token-doc/doc/sso/sso-h5.md b/sa-token-doc/doc/sso/sso-h5.md index da701640..4b2ca2ee 100644 --- a/sa-token-doc/doc/sso/sso-h5.md +++ b/sa-token-doc/doc/sso/sso-h5.md @@ -21,16 +21,16 @@ public class H5Controller { } // 返回SSO认证中心登录地址 - @RequestMapping("/getSsoAuthUrl") + @RequestMapping("/sso/getSsoAuthUrl") public SaResult getSsoAuthUrl(String clientLoginUrl) { String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, ""); return SaResult.data(serverAuthUrl); } // 根据ticket进行登录 - @RequestMapping("/doLoginByTicket") + @RequestMapping("/sso/doLoginByTicket") public SaResult doLoginByTicket(String ticket) { - Object loginId = SaSsoHandle.checkTicket(ticket, "/doLoginByTicket"); + Object loginId = SaSsoHandle.checkTicket(ticket, "/sso/doLoginByTicket"); if(loginId != null) { StpUtil.login(loginId); return SaResult.data(StpUtil.getTokenValue()); diff --git a/sa-token-doc/doc/sso/sso-type1.md b/sa-token-doc/doc/sso/sso-type1.md index b70348d8..da45b819 100644 --- a/sa-token-doc/doc/sso/sso-type1.md +++ b/sa-token-doc/doc/sso/sso-type1.md @@ -109,8 +109,8 @@ public class SsoClientController { // SSO-Client端:首页 @RequestMapping("/") public String index() { - String authUrl = SaSsoManager.getConfig().getAuthUrl(); - String solUrl = SaSsoManager.getConfig().getSloUrl(); + String authUrl = SaSsoManager.getConfig().splicingAuthUrl(); + String solUrl = SaSsoManager.getConfig().splicingSloUrl(); String str = "

Sa-Token SSO-Client 应用端

" + "

当前会话是否登录:" + StpUtil.isLogin() + "

" + "

登录 " + From 3f91fa4045008eab6064cbe2f3fdce50073d4be2 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sat, 20 Aug 2022 12:11:25 +0800 Subject: [PATCH 115/144] =?UTF-8?q?=E5=AE=8C=E5=96=84SSO=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=B1=BB=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/dev33/satoken/config/SaSsoConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java index c233f4fb..0d8253d8 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java @@ -377,6 +377,8 @@ public class SaSsoConfig implements Serializable { /** * SSO-Client端:自定义校验Ticket返回值的处理逻辑 (每次从认证中心获取校验Ticket的结果后调用) + *

参数:loginId, back + *

返回值:返回给前端的值 */ public BiFunction ticketResultHandle = null; From e3465870ee8c48e7105e6a4d8451b26091fcc2ae Mon Sep 17 00:00:00 2001 From: fanpeng Date: Sat, 20 Aug 2022 21:26:57 +0800 Subject: [PATCH 116/144] =?UTF-8?q?=E6=96=B0=E5=A2=9Etoken=E8=B6=85?= =?UTF-8?q?=E6=97=B6=E6=9B=B4=E6=96=B0=E4=BA=8B=E4=BB=B6=E7=9B=91=E5=90=AC?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev33/satoken/listener/SaTokenEventCenter.java | 14 +++++++++++++- .../cn/dev33/satoken/listener/SaTokenListener.java | 10 +++++++++- .../listener/SaTokenListenerForConsolePrint.java | 12 ++++++++++++ .../satoken/listener/SaTokenListenerForSimple.java | 5 +++++ .../main/java/cn/dev33/satoken/stp/StpLogic.java | 3 +++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java index cd708942..7a83da71 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java @@ -214,5 +214,17 @@ public class SaTokenEventCenter { listener.doLogoutSession(id); } } - + + /** + * 每次renew timeout时触发 + * + * @param tokenValue + * @param loginId + * @param timeout + */ + public static void doRenewTimeout(String tokenValue, Object loginId, long timeout) { + for (SaTokenListener listener : listenerList) { + listener.doRenewTimeout(tokenValue, loginId, timeout); + } + } } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java index 4fdff910..2912241f 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java @@ -69,5 +69,13 @@ public interface SaTokenListener { * @param id SessionId */ public void doLogoutSession(String id); - + + /** + * 执行renew超时时间操作的时触发 + * + * @param tokenValue + * @param loginId + * @param timeout + */ + public void doRenewTimeout(String tokenValue, Object loginId, long timeout); } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java index c13229c2..b4940075 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java @@ -78,6 +78,18 @@ public class SaTokenListenerForConsolePrint implements SaTokenListener { println("Session[" + id + "]注销成功"); } + /** + * 每次更新超时时间后触发 + * + * @param tokenValue + * @param loginId + * @param timeout + */ + @Override + public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { + println("帐号[" + loginId + "]更新超时时间成功!"); + } + /** * 日志输出的前缀 */ diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java index 3ad3b7a6..9f999067 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java @@ -52,4 +52,9 @@ public class SaTokenListenerForSimple implements SaTokenListener { } + @Override + public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { + + } + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 985dfa55..9f1377e7 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -1219,6 +1219,9 @@ public class StpLogic { if(isOpenActivityCheck()) { dao.updateTimeout(splicingKeyLastActivityTime(tokenValue), timeout); } + + // 通知更新超时事件 + SaTokenEventCenter.doRenewTimeout(tokenValue, loginId, timeout); } // ------------------- 角色验证操作 ------------------- From b2a925811c62c40f4b1dae27ba05e9a3add720af Mon Sep 17 00:00:00 2001 From: fanpeng Date: Sat, 20 Aug 2022 21:37:21 +0800 Subject: [PATCH 117/144] =?UTF-8?q?=E6=96=B0=E5=A2=9Etoken=E8=B6=85?= =?UTF-8?q?=E6=97=B6=E6=9B=B4=E6=96=B0=E4=BA=8B=E4=BB=B6=E7=9B=91=E5=90=AC?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/up/global-listener.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sa-token-doc/doc/up/global-listener.md b/sa-token-doc/doc/up/global-listener.md index 1e202cfd..66af3983 100644 --- a/sa-token-doc/doc/up/global-listener.md +++ b/sa-token-doc/doc/up/global-listener.md @@ -78,7 +78,12 @@ public class MySaTokenListener implements SaTokenListener { public void doLogoutSession(String id) { System.out.println("---------- 自定义侦听器实现 doLogoutSession"); } - + + /** 每次更新token超时时间时触发 */ + @Override + public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { + System.out.println("帐号[" + loginId + "]更新超时时间成功!"); + } } ``` From 8e5e983075827f1be0b3cb0ee1d466e65c25e7f2 Mon Sep 17 00:00:00 2001 From: "Mr.Wang" <1581306992@qq.com> Date: Sat, 20 Aug 2022 16:06:38 +0000 Subject: [PATCH 118/144] update sa-token-doc/doc/more/link.md. Signed-off-by: Mr.Wang <1581306992@qq.com> --- sa-token-doc/doc/more/link.md | 1 + 1 file changed, 1 insertion(+) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index f269b1be..fb560065 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -76,6 +76,7 @@ - [[ chaos ]](https://gitee.com/qishanor/chaos):一个基于 SpringBoot + Sa-Token + Mybatis-Plus的快速开发框架,前端vue-element-avue,内置代码生成器,代码最简洁,最佳学习实践方案。 +- [[ Pig-Satoken ]](https://gitee.com/wchenyang/cloud-satoken):重写Pig授权方式为Satoken,其他代码不变 From ffcad7da6f15488cd8ee5ea1d4ad7c2123d42ee8 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 21 Aug 2022 07:03:26 +0800 Subject: [PATCH 119/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20SaInterceptor=20?= =?UTF-8?q?=E7=BB=BC=E5=90=88=E6=8B=A6=E6=88=AA=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/interceptor/SaInterceptor.java | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java new file mode 100644 index 00000000..3889dffa --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java @@ -0,0 +1,108 @@ +package cn.dev33.satoken.interceptor; + +import java.lang.reflect.Method; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import cn.dev33.satoken.exception.BackResultException; +import cn.dev33.satoken.exception.StopMatchException; +import cn.dev33.satoken.fun.SaParamFunction; +import cn.dev33.satoken.strategy.SaStrategy; + +/** + * Sa-Token 综合拦截器,提供注解鉴权和路由拦截鉴权能力 + * + * @author kong + * @since: 2022-8-21 + */ +public class SaInterceptor implements HandlerInterceptor { + + /** + * 是否打开注解鉴权 + */ + public boolean isAnnotation = true; + + + + + /** + * 认证函数:每次请求执行 + *

参数:路由处理函数指针 + */ + public SaParamFunction auth = handler -> {}; + + /** + * 创建一个 Sa-Token 综合拦截器,默认带有注解鉴权能力 + */ + public SaInterceptor() { + } + + /** + * 创建一个 Sa-Token 综合拦截器,默认带有注解鉴权能力 + * @param auth 认证函数,每次请求执行 + */ + public SaInterceptor(SaParamFunction auth) { + this.auth = auth; + } + + /** + * 设置是否打开注解鉴权 + * @param isAnnotation / + * @return 对象自身 + */ + public SaInterceptor isAnnotation(boolean isAnnotation) { + this.isAnnotation = isAnnotation; + return this; + } + + /** + * 写入[认证函数]: 每次请求执行 + * @param auth / + * @return 对象自身 + */ + public SaInterceptor setAuth(SaParamFunction auth) { + this.auth = auth; + return this; + } + + + // ----------------- 验证方法 ----------------- + + /** + * 每次请求之前触发的方法 + */ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + + try { + + // 获取此请求对应的 Method 处理函数 + if(handler instanceof HandlerMethod) { + Method method = ((HandlerMethod) handler).getMethod(); + SaStrategy.me.checkMethodAnnotation.accept(method); + } + + // Auth 校验 + auth.run(handler); + + } catch (StopMatchException e) { + // 停止匹配,进入Controller + } catch (BackResultException e) { + // 停止匹配,向前端输出结果 + if(response.getContentType() == null) { + response.setContentType("text/plain; charset=utf-8"); + } + response.getWriter().print(e.getMessage()); + return false; + } + + // 通过验证 + return true; + } + +} From be18498119a983ff834565ef6de164ca1b540bd9 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 21 Aug 2022 07:11:33 +0800 Subject: [PATCH 120/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20SaIgnore=20?= =?UTF-8?q?=E5=BF=BD=E7=95=A5=E9=89=B4=E6=9D=83=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/dev33/satoken/annotation/SaIgnore.java | 20 +++++++++++++++++++ .../cn/dev33/satoken/strategy/SaStrategy.java | 11 ++++++++++ .../cn/dev33/satoken/aop/SaCheckAspect.java | 16 +++++++++++++-- .../satoken/interceptor/SaInterceptor.java | 15 ++++++++++---- 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaIgnore.java diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaIgnore.java b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaIgnore.java new file mode 100644 index 00000000..3e31915f --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaIgnore.java @@ -0,0 +1,20 @@ +package cn.dev33.satoken.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 忽略认证:表示被修饰的方法或类无需进行注解认证和路由拦截认证 + * + *

请注意:此注解的忽略效果只针对 SaInterceptor拦截器 和 APO注解鉴权 生效,对自定义拦截器与过滤器不生效

+ * + * @author kong + * @since: 2022-8-21 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE }) +public @interface SaIgnore { + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java index 9f8e79d5..eaef034b 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java @@ -15,6 +15,7 @@ import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckRole; import cn.dev33.satoken.annotation.SaCheckSafe; +import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.basic.SaBasicUtil; import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.util.SaFoxUtil; @@ -179,6 +180,16 @@ public final class SaStrategy { return element.getAnnotation(annotationClass); }; + /** + * 判断一个 Method 或其所属 Class 是否包含指定注解 + * + *

参数 [Method, 注解] + */ + public BiFunction isAnnotationPresent = (method, annotationClass) -> { + return me.getAnnotation.apply(method, SaIgnore.class) != null || + me.getAnnotation.apply(method.getDeclaringClass(), SaIgnore.class) != null; + }; + /** * 拼接两个url *

例如:url1=http://domain.cn,url2=/sso/auth,则返回:http://domain.cn/sso/auth diff --git a/sa-token-plugin/sa-token-spring-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java b/sa-token-plugin/sa-token-spring-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java index 309435e0..92ce5cb6 100644 --- a/sa-token-plugin/sa-token-spring-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java +++ b/sa-token-plugin/sa-token-spring-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java @@ -1,5 +1,7 @@ package cn.dev33.satoken.aop; +import java.lang.reflect.Method; + import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -8,6 +10,7 @@ import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.util.SaTokenConsts; @@ -54,9 +57,18 @@ public class SaCheckAspect { @Around("pointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { - // 注解鉴权 + // 获取对应的 Method 处理函数 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); - SaStrategy.me.checkMethodAnnotation.accept(signature.getMethod()); + Method method = signature.getMethod(); + + // 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权 + if(SaStrategy.me.isAnnotationPresent.apply(method, SaIgnore.class)) { + // ... + } else { + // 注解鉴权 + SaStrategy.me.checkMethodAnnotation.accept(method); + } + try { // 执行原有逻辑 diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java index 3889dffa..af60c0d7 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java @@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; +import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.exception.BackResultException; import cn.dev33.satoken.exception.StopMatchException; import cn.dev33.satoken.fun.SaParamFunction; @@ -26,9 +27,6 @@ public class SaInterceptor implements HandlerInterceptor { */ public boolean isAnnotation = true; - - - /** * 认证函数:每次请求执行 *

参数:路由处理函数指针 @@ -84,7 +82,16 @@ public class SaInterceptor implements HandlerInterceptor { // 获取此请求对应的 Method 处理函数 if(handler instanceof HandlerMethod) { Method method = ((HandlerMethod) handler).getMethod(); - SaStrategy.me.checkMethodAnnotation.accept(method); + + // 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权 + if(SaStrategy.me.isAnnotationPresent.apply(method, SaIgnore.class)) { + return true; + } + + // 注解校验 + if(isAnnotation) { + SaStrategy.me.checkMethodAnnotation.accept(method); + } } // Auth 校验 From 434803de2e2604ba3f4157d35905f03c921400d8 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 21 Aug 2022 07:12:20 +0800 Subject: [PATCH 121/144] =?UTF-8?q?SaAnnotationInterceptor=20=E4=B8=8E=20S?= =?UTF-8?q?aRouteInterceptor=20=E6=A0=87=E6=B3=A8=E4=B8=BA=E8=BF=87?= =?UTF-8?q?=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/pj/satoken/SaTokenConfigure.java | 10 +++++----- .../src/main/java/com/pj/satoken/SaTokenConfigure.java | 8 ++++---- .../src/main/java/com/pj/satoken/SaTokenConfigure.java | 8 ++++---- .../satoken/interceptor/SaAnnotationInterceptor.java | 5 +++-- .../dev33/satoken/interceptor/SaRouteInterceptor.java | 3 ++- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/satoken/SaTokenConfigure.java index b4069300..29a77d96 100644 --- a/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/satoken/SaTokenConfigure.java +++ b/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/satoken/SaTokenConfigure.java @@ -5,7 +5,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import cn.dev33.satoken.interceptor.SaAnnotationInterceptor; +import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.jwt.StpLogicJwtForSimple; import cn.dev33.satoken.stp.StpLogic; @@ -17,14 +17,14 @@ import cn.dev33.satoken.stp.StpLogic; */ @Configuration public class SaTokenConfigure implements WebMvcConfigurer { - + /** - * 注册Sa-Token 的拦截器,打开注解式鉴权功能 + * 注册 Sa-Token 拦截器打开注解鉴权功能 */ @Override public void addInterceptors(InterceptorRegistry registry) { - // 注册注解拦截器 - registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**"); + // 注册 Sa-Token 拦截器打开注解鉴权功能 + registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); } /** diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/SaTokenConfigure.java index 5f3212e7..50358e17 100644 --- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/SaTokenConfigure.java +++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/SaTokenConfigure.java @@ -11,7 +11,7 @@ import com.pj.util.AjaxJson; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.filter.SaServletFilter; -import cn.dev33.satoken.interceptor.SaAnnotationInterceptor; +import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.strategy.SaStrategy; @@ -24,12 +24,12 @@ import cn.dev33.satoken.strategy.SaStrategy; public class SaTokenConfigure implements WebMvcConfigurer { /** - * 注册Sa-Token 的拦截器,打开注解式鉴权功能 + * 注册 Sa-Token 拦截器打开注解鉴权功能 */ @Override public void addInterceptors(InterceptorRegistry registry) { - // 注册注解拦截器 - registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**"); + // 注册 Sa-Token 拦截器打开注解鉴权功能 + registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); } /** diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java index 5f3212e7..50358e17 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java @@ -11,7 +11,7 @@ import com.pj.util.AjaxJson; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.filter.SaServletFilter; -import cn.dev33.satoken.interceptor.SaAnnotationInterceptor; +import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.strategy.SaStrategy; @@ -24,12 +24,12 @@ import cn.dev33.satoken.strategy.SaStrategy; public class SaTokenConfigure implements WebMvcConfigurer { /** - * 注册Sa-Token 的拦截器,打开注解式鉴权功能 + * 注册 Sa-Token 拦截器打开注解鉴权功能 */ @Override public void addInterceptors(InterceptorRegistry registry) { - // 注册注解拦截器 - registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**"); + // 注册 Sa-Token 拦截器打开注解鉴权功能 + registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); } /** diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java index 28ebc964..a4a1d9bc 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java @@ -11,10 +11,11 @@ import org.springframework.web.servlet.HandlerInterceptor; import cn.dev33.satoken.strategy.SaStrategy; /** - * 注解式鉴权 - 拦截器 + * Sa-Token 注解式鉴权 - 拦截器 * * @author kong */ +@Deprecated public class SaAnnotationInterceptor implements HandlerInterceptor { /** @@ -30,7 +31,7 @@ public class SaAnnotationInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - // 获取处理method + // 获取处理 Method if (handler instanceof HandlerMethod == false) { return true; } diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java index 8ec0941c..385566b2 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java @@ -13,9 +13,10 @@ import cn.dev33.satoken.servlet.model.SaResponseForServlet; import cn.dev33.satoken.stp.StpUtil; /** - * sa-token基于路由的拦截式鉴权 + * Sa-Token 拦截式鉴权 - 拦截器 * @author kong */ +@Deprecated public class SaRouteInterceptor implements HandlerInterceptor { /** From bdb671d3c269ee6b8f9ba4face4c0d362ccced27 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 21 Aug 2022 07:27:15 +0800 Subject: [PATCH 122/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/link.md | 2 +- .../satoken/interceptor/SaAnnotationInterceptor.java | 1 + .../java/cn/dev33/satoken/interceptor/SaInterceptor.java | 9 ++++----- .../cn/dev33/satoken/interceptor/SaRouteInterceptor.java | 4 +++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index fb560065..d1c688a4 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -76,7 +76,7 @@ - [[ chaos ]](https://gitee.com/qishanor/chaos):一个基于 SpringBoot + Sa-Token + Mybatis-Plus的快速开发框架,前端vue-element-avue,内置代码生成器,代码最简洁,最佳学习实践方案。 -- [[ Pig-Satoken ]](https://gitee.com/wchenyang/cloud-satoken):重写Pig授权方式为Satoken,其他代码不变 +- [[ Pig-Satoken ]](https://gitee.com/wchenyang/cloud-satoken):重写 Pig 授权方式为 Sa-Token,其他代码不变。 diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java index a4a1d9bc..afa7fa3b 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java @@ -12,6 +12,7 @@ import cn.dev33.satoken.strategy.SaStrategy; /** * Sa-Token 注解式鉴权 - 拦截器 + *

[ 当前拦截器写法已过期,可能将在以后的版本删除,推荐升级为 SaInterceptor ]

* * @author kong */ diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java index af60c0d7..c1836c82 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java @@ -79,8 +79,9 @@ public class SaInterceptor implements HandlerInterceptor { try { - // 获取此请求对应的 Method 处理函数 - if(handler instanceof HandlerMethod) { + if(isAnnotation && handler instanceof HandlerMethod) { + + // 获取此请求对应的 Method 处理函数 Method method = ((HandlerMethod) handler).getMethod(); // 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权 @@ -89,9 +90,7 @@ public class SaInterceptor implements HandlerInterceptor { } // 注解校验 - if(isAnnotation) { - SaStrategy.me.checkMethodAnnotation.accept(method); - } + SaStrategy.me.checkMethodAnnotation.accept(method); } // Auth 校验 diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java index 385566b2..4ce53f11 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java @@ -13,7 +13,9 @@ import cn.dev33.satoken.servlet.model.SaResponseForServlet; import cn.dev33.satoken.stp.StpUtil; /** - * Sa-Token 拦截式鉴权 - 拦截器 + * Sa-Token 拦截式鉴权 - 拦截器 + *

[ 当前拦截器写法已过期,可能将在以后的版本删除,推荐升级为 SaInterceptor ]

+ * * @author kong */ @Deprecated From 0cd877c6e61a479100e2e584acfabdf41e307454 Mon Sep 17 00:00:00 2001 From: fanpeng Date: Sun, 21 Aug 2022 10:15:45 +0800 Subject: [PATCH 123/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B3=A8=E8=A7=A3?= =?UTF-8?q?=E6=8B=A6=E6=88=AA=E5=99=A8=E4=B8=8D=E7=94=9F=E6=95=88=E7=9A=84?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E8=A7=A3=E5=86=B3=E6=96=B9=E6=A1=88=E8=AF=B4?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/common-questions.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sa-token-doc/doc/more/common-questions.md b/sa-token-doc/doc/more/common-questions.md index 7954cd42..9874d412 100644 --- a/sa-token-doc/doc/more/common-questions.md +++ b/sa-token-doc/doc/more/common-questions.md @@ -47,8 +47,13 @@ ### 加了注解进行鉴权认证,不生效? -注解鉴权功能默认关闭,两种方式任选其一进行打开:注册注解拦截器、集成AOP模块,参考:[注解式鉴权](/use/at-check), -如果已经打开仍然没有效果,加群说明一下复现步骤 +1. 注解鉴权功能默认关闭,两种方式任选其一进行打开:注册注解拦截器、集成AOP模块,参考:[注解式鉴权](/use/at-check) +2. 在Spring环境中, 如果同时配置了`WebMvcConfigurer`和`WebMvcConfigurationSupport`时, 也会导致拦截器失效. + + **常见场景**: swagger相关静态资源开放, 很多教程会在`WebMvcConfigurationSupport`中设置`addResourceHandlers`方法以开放静态资源映射, 同时Sa-Token相关配置添加了`WebMvcConfigurer`配置`addInterceptors`方法注册拦截器, 这样就会导致拦截器失效. + + **解决方案**: `WebMvcConfigurer`和`WebMvcConfigurationSupport`只选一个配置, 建议统一通过实现`WebMvcConfigurer`接口进行配置. +4. 如果以上步骤处理后仍然没有效果,加群说明一下复现步骤 ### 有时候我不加 Token 也可以通过鉴权,请问是怎么回事? From 87e26a3e6f6513bd3e5e348589b3e1051f081a0c Mon Sep 17 00:00:00 2001 From: fanpeng Date: Sun, 21 Aug 2022 10:21:15 +0800 Subject: [PATCH 124/144] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B3=A8=E8=A7=A3?= =?UTF-8?q?=E6=8B=A6=E6=88=AA=E5=99=A8=E4=B8=8D=E7=94=9F=E6=95=88=E7=9A=84?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E8=A7=A3=E5=86=B3=E6=96=B9=E6=A1=88=E8=AF=B4?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/more/common-questions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/more/common-questions.md b/sa-token-doc/doc/more/common-questions.md index 9874d412..965f6e9d 100644 --- a/sa-token-doc/doc/more/common-questions.md +++ b/sa-token-doc/doc/more/common-questions.md @@ -50,7 +50,7 @@ 1. 注解鉴权功能默认关闭,两种方式任选其一进行打开:注册注解拦截器、集成AOP模块,参考:[注解式鉴权](/use/at-check) 2. 在Spring环境中, 如果同时配置了`WebMvcConfigurer`和`WebMvcConfigurationSupport`时, 也会导致拦截器失效. - **常见场景**: swagger相关静态资源开放, 很多教程会在`WebMvcConfigurationSupport`中设置`addResourceHandlers`方法以开放静态资源映射, 同时Sa-Token相关配置添加了`WebMvcConfigurer`配置`addInterceptors`方法注册拦截器, 这样就会导致拦截器失效. + **常见场景**: 很多项目中会在`WebMvcConfigurationSupport`中配置`addResourceHandlers`方法开放Swagger等相关静态资源映射, 同时基于Sa-Token添加了`WebMvcConfigurer`配置`addInterceptors`方法注册注解拦截器, 这样会导致注解拦截器失效. **解决方案**: `WebMvcConfigurer`和`WebMvcConfigurationSupport`只选一个配置, 建议统一通过实现`WebMvcConfigurer`接口进行配置. 4. 如果以上步骤处理后仍然没有效果,加群说明一下复现步骤 From f0b49b451a5975008adcbd38ddf7e8e97116d524 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 21 Aug 2022 15:36:09 +0800 Subject: [PATCH 125/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/dev33/satoken/listener/SaTokenEventCenter.java | 11 ++++++----- .../cn/dev33/satoken/listener/SaTokenListener.java | 11 ++++++----- .../listener/SaTokenListenerForConsolePrint.java | 8 ++------ sa-token-doc/doc/up/global-listener.md | 4 ++-- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java index 7a83da71..5c3c16c2 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java @@ -216,15 +216,16 @@ public class SaTokenEventCenter { } /** - * 每次renew timeout时触发 - * - * @param tokenValue - * @param loginId - * @param timeout + * 每次Token续期时触发 + * + * @param tokenValue token 值 + * @param loginId 账号id + * @param timeout 续期时间 */ public static void doRenewTimeout(String tokenValue, Object loginId, long timeout) { for (SaTokenListener listener : listenerList) { listener.doRenewTimeout(tokenValue, loginId, timeout); } } + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java index 2912241f..25fdcdfd 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java @@ -71,11 +71,12 @@ public interface SaTokenListener { public void doLogoutSession(String id); /** - * 执行renew超时时间操作的时触发 - * - * @param tokenValue - * @param loginId - * @param timeout + * 每次Token续期时触发 + * + * @param tokenValue token 值 + * @param loginId 账号id + * @param timeout 续期时间 */ public void doRenewTimeout(String tokenValue, Object loginId, long timeout); + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java index b4940075..378ac351 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java @@ -79,15 +79,11 @@ public class SaTokenListenerForConsolePrint implements SaTokenListener { } /** - * 每次更新超时时间后触发 - * - * @param tokenValue - * @param loginId - * @param timeout + * 每次Token续期时触发 */ @Override public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { - println("帐号[" + loginId + "]更新超时时间成功!"); + println("帐号[" + loginId + "],Token=" + tokenValue + " 续期timeout成功!"); } /** diff --git a/sa-token-doc/doc/up/global-listener.md b/sa-token-doc/doc/up/global-listener.md index 66af3983..3e6472ca 100644 --- a/sa-token-doc/doc/up/global-listener.md +++ b/sa-token-doc/doc/up/global-listener.md @@ -79,10 +79,10 @@ public class MySaTokenListener implements SaTokenListener { System.out.println("---------- 自定义侦听器实现 doLogoutSession"); } - /** 每次更新token超时时间时触发 */ + /** 每次Token续期时触发 */ @Override public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { - System.out.println("帐号[" + loginId + "]更新超时时间成功!"); + System.out.println("---------- 自定义侦听器实现 doRenewTimeout"); } } ``` From 3addd684d64f50a07966b401ae5d8f74b4b4eab4 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 21 Aug 2022 15:38:06 +0800 Subject: [PATCH 126/144] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=EF=BC=9Asa-token-dao-redis-string=20->=20sa-?= =?UTF-8?q?token-dao-redis-fastjson?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-plugin/pom.xml | 2 +- .../.gitignore | 0 .../pom.xml | 2 +- .../satoken/dao/SaTokenDaoRedisFastjson.java} | 17 ++++++++++------- .../main/resources/META-INF/spring.factories | 2 +- .../satoken/dao/SaTokenDaoRedisJackson.java | 12 +++++++----- .../cn/dev33/satoken/dao/SaTokenDaoRedis.java | 13 ++++++++----- 7 files changed, 28 insertions(+), 20 deletions(-) rename sa-token-plugin/{sa-token-dao-redis-string => sa-token-dao-redis-fastjson}/.gitignore (100%) rename sa-token-plugin/{sa-token-dao-redis-string => sa-token-dao-redis-fastjson}/pom.xml (95%) rename sa-token-plugin/{sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java => sa-token-dao-redis-fastjson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisFastjson.java} (95%) rename sa-token-plugin/{sa-token-dao-redis-string => sa-token-dao-redis-fastjson}/src/main/resources/META-INF/spring.factories (59%) diff --git a/sa-token-plugin/pom.xml b/sa-token-plugin/pom.xml index 61ad0051..36c831c7 100644 --- a/sa-token-plugin/pom.xml +++ b/sa-token-plugin/pom.xml @@ -21,8 +21,8 @@ sa-token-alone-redis sa-token-dao-redis sa-token-dao-redis-jackson + sa-token-dao-redis-fastjson sa-token-dao-redisx - sa-token-dao-redis-string sa-token-dialect-thymeleaf sa-token-sso sa-token-oauth2 diff --git a/sa-token-plugin/sa-token-dao-redis-string/.gitignore b/sa-token-plugin/sa-token-dao-redis-fastjson/.gitignore similarity index 100% rename from sa-token-plugin/sa-token-dao-redis-string/.gitignore rename to sa-token-plugin/sa-token-dao-redis-fastjson/.gitignore diff --git a/sa-token-plugin/sa-token-dao-redis-string/pom.xml b/sa-token-plugin/sa-token-dao-redis-fastjson/pom.xml similarity index 95% rename from sa-token-plugin/sa-token-dao-redis-string/pom.xml rename to sa-token-plugin/sa-token-dao-redis-fastjson/pom.xml index fbf0d58d..97a4d7f6 100644 --- a/sa-token-plugin/sa-token-dao-redis-string/pom.xml +++ b/sa-token-plugin/sa-token-dao-redis-fastjson/pom.xml @@ -10,7 +10,7 @@ 4.0.0 - sa-token-dao-redix-string + sa-token-dao-redis-fastjson diff --git a/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java b/sa-token-plugin/sa-token-dao-redis-fastjson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisFastjson.java similarity index 95% rename from sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java rename to sa-token-plugin/sa-token-dao-redis-fastjson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisFastjson.java index 9a588605..ff68bdde 100644 --- a/sa-token-plugin/sa-token-dao-redis-string/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisString.java +++ b/sa-token-plugin/sa-token-dao-redis-fastjson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisFastjson.java @@ -21,7 +21,7 @@ import java.util.concurrent.TimeUnit; * */ @Component -public class SaTokenDaoRedisString implements SaTokenDao { +public class SaTokenDaoRedisFastjson implements SaTokenDao { /** * String专用 @@ -29,7 +29,7 @@ public class SaTokenDaoRedisString implements SaTokenDao { public StringRedisTemplate stringRedisTemplate; /** - * Objecy专用 + * Object专用 */ public StringRedisTemplate objectRedisTemplate; @@ -40,6 +40,11 @@ public class SaTokenDaoRedisString implements SaTokenDao { @Autowired public void init(RedisConnectionFactory connectionFactory) { + // 不重复初始化 + if(this.isInit) { + return; + } + // 指定相应的序列化方案 StringRedisSerializer keySerializer = new StringRedisSerializer(); StringRedisSerializer valueSerializer = new StringRedisSerializer(); @@ -57,11 +62,9 @@ public class SaTokenDaoRedisString implements SaTokenDao { template.afterPropertiesSet(); // 开始初始化相关组件 - if(!this.isInit) { - this.stringRedisTemplate = stringTemplate; - this.objectRedisTemplate = template; - this.isInit = true; - } + this.stringRedisTemplate = stringTemplate; + this.objectRedisTemplate = template; + this.isInit = true; } diff --git a/sa-token-plugin/sa-token-dao-redis-string/src/main/resources/META-INF/spring.factories b/sa-token-plugin/sa-token-dao-redis-fastjson/src/main/resources/META-INF/spring.factories similarity index 59% rename from sa-token-plugin/sa-token-dao-redis-string/src/main/resources/META-INF/spring.factories rename to sa-token-plugin/sa-token-dao-redis-fastjson/src/main/resources/META-INF/spring.factories index 09ff20cb..b88e60f8 100644 --- a/sa-token-plugin/sa-token-dao-redis-string/src/main/resources/META-INF/spring.factories +++ b/sa-token-plugin/sa-token-dao-redis-fastjson/src/main/resources/META-INF/spring.factories @@ -1 +1 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.dao.SaTokenDaoRedisString \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.dao.SaTokenDaoRedisFastjson \ No newline at end of file diff --git a/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java b/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java index 98c3a2a4..d81207f5 100644 --- a/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java +++ b/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java @@ -69,6 +69,10 @@ public class SaTokenDaoRedisJackson implements SaTokenDao { @Autowired public void init(RedisConnectionFactory connectionFactory) { + // 不重复初始化 + if(this.isInit) { + return; + } // 指定相应的序列化方案 StringRedisSerializer keySerializer = new StringRedisSerializer(); @@ -112,11 +116,9 @@ public class SaTokenDaoRedisJackson implements SaTokenDao { template.afterPropertiesSet(); // 开始初始化相关组件 - if(this.isInit == false) { - this.stringRedisTemplate = stringTemplate; - this.objectRedisTemplate = template; - this.isInit = true; - } + this.stringRedisTemplate = stringTemplate; + this.objectRedisTemplate = template; + this.isInit = true; } diff --git a/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java b/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java index a4bf7870..dcfd6aee 100644 --- a/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java +++ b/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java @@ -41,6 +41,11 @@ public class SaTokenDaoRedis implements SaTokenDao { @Autowired public void init(RedisConnectionFactory connectionFactory) { + // 不重复初始化 + if(this.isInit) { + return; + } + // 指定相应的序列化方案 StringRedisSerializer keySerializer = new StringRedisSerializer(); JdkSerializationRedisSerializer valueSerializer = new JdkSerializationRedisSerializer(); @@ -58,11 +63,9 @@ public class SaTokenDaoRedis implements SaTokenDao { template.afterPropertiesSet(); // 开始初始化相关组件 - if(this.isInit == false) { - this.stringRedisTemplate = stringTemplate; - this.objectRedisTemplate = template; - this.isInit = true; - } + this.stringRedisTemplate = stringTemplate; + this.objectRedisTemplate = template; + this.isInit = true; } From 4a9a5e4580eb000b8f668a4d97fd10db872699c0 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 21 Aug 2022 15:40:39 +0800 Subject: [PATCH 127/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/plugin/dao-extend.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sa-token-doc/doc/plugin/dao-extend.md b/sa-token-doc/doc/plugin/dao-extend.md index 50b0e86c..25e0dfae 100644 --- a/sa-token-doc/doc/plugin/dao-extend.md +++ b/sa-token-doc/doc/plugin/dao-extend.md @@ -6,12 +6,13 @@ 框架已提供的集成包包括: -- 默认方式:储存在内存中,位于core核心包 -- sa-token-dao-redis:Redis集成包,使用 jdk 默认序列化方式 -- sa-token-dao-redis-jackson:Redis集成包,使用 jackson 序列化方式 -- sa-token-dao-redisx:Redisx 集成包 +- 默认方式:储存在内存中,位于core核心包。 +- sa-token-dao-redis:Redis集成包,使用 jdk 默认序列化方式。 +- sa-token-dao-redis-jackson:Redis集成包,使用 jackson 序列化方式。 +- sa-token-dao-redisx:Redisx 集成包。 +- sa-token-dao-redis-fastjson:Redis集成包,使用 fastjson 序列化方式。 -有关Redis集成,详细参考:[集成Redis](/up/integ-redis),更多存储方式欢迎提交PR +有关 Redis 集成,详细参考:[集成Redis](/up/integ-redis),更多存储方式欢迎提交PR From 7419846eb3c339e61ae324899509cc669d403d03 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 22 Aug 2022 05:21:02 +0800 Subject: [PATCH 128/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/_sidebar.md | 3 +- sa-token-doc/doc/oauth2/oauth2-dev.md | 3 ++ sa-token-doc/doc/up/many-account.md | 4 +- sa-token-doc/doc/use/config.md | 69 ++++++++++++++++++++++----- sa-token-doc/doc/use/login-auth.md | 2 +- 5 files changed, 65 insertions(+), 16 deletions(-) diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 1823a91f..a30019d5 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -29,8 +29,7 @@ - [会话治理](/up/search-session) - [全局侦听器](/up/global-listener) - [全局过滤器](/up/global-filter) - - [多账户认证](/up/many-account) - + - [多账号认证](/up/many-account) - **单点登录** - [单点登录简述](/sso/readme) diff --git a/sa-token-doc/doc/oauth2/oauth2-dev.md b/sa-token-doc/doc/oauth2/oauth2-dev.md index 4952d237..b8ea17e1 100644 --- a/sa-token-doc/doc/oauth2/oauth2-dev.md +++ b/sa-token-doc/doc/oauth2/oauth2-dev.md @@ -31,6 +31,9 @@ SaOAuth2Util.refreshAccessToken(refreshToken); // 构建 Client-Token SaOAuth2Util.generateClientToken(clientId, scope); +// 校验 Client-Token 是否含有指定 Scope +SaOAuth2Util.checkClientTokenScope(clientToken, scopes); + // 回收 Access-Token SaOAuth2Util.revokeAccessToken(accessToken); diff --git a/sa-token-doc/doc/up/many-account.md b/sa-token-doc/doc/up/many-account.md index f0bb2905..df536176 100644 --- a/sa-token-doc/doc/up/many-account.md +++ b/sa-token-doc/doc/up/many-account.md @@ -1,11 +1,11 @@ -# 多账户认证 +# 多账号认证 --- ### 1、需求场景 有的时候,我们会在一个项目中设计两套账号体系,比如一个电商系统的 `user表` 和 `admin表`, 在这种场景下,如果两套账号我们都使用 `StpUtil` 类的API进行登录鉴权,那么势必会发生逻辑冲突。 -在Sa-Token中,这个问题的模型叫做:多账户体系认证。 +在Sa-Token中,这个问题的模型叫做:多账号体系认证。 要解决这个问题,我们必须有一个合理的机制将这两套账号的授权给区分开,让它们互不干扰才行。 diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index b39028e6..8b568a7a 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -82,13 +82,13 @@ PS:两者的区别在于:**`模式1会覆盖yml中的配置,模式2会与y | activityTimeout | long | -1 | Token 临时有效期 (指定时间内无操作就视为token过期) 单位: 秒, 默认-1 代表不限制 (例如可以设置为1800代表30分钟内无操作就过期) [参考:token有效期详解](/fun/token-timeout) | | isConcurrent | Boolean | true | 是否允许同一账号并发登录 (为 true 时允许一起登录,为 false 时新登录挤掉旧登录) | | isShare | Boolean | true | 在多人登录同一账号时,是否共用一个token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) | -| maxLoginCount | int | 12 | 同一账号最大登录数量,-1代表不限 (只有在 `isConcurrent=true`, `isShare=false` 时此配置才有效),[详解](/use/config?id=maxlogincount) | +| maxLoginCount | int | 12 | 同一账号最大登录数量,-1代表不限 (只有在 `isConcurrent=true`, `isShare=false` 时此配置才有效),[详解](/use/config?id=配置项详解:maxlogincount) | | isReadBody | Boolean | true | 是否尝试从 请求体 里读取 Token | | isReadHead | Boolean | true | 是否尝试从 header 里读取 Token | | isReadCookie | Boolean | true | 是否尝试从 cookie 里读取 Token,此值为 false 后,`StpUtil.login(id)` 登录时也不会再往前端注入Cookie | | tokenStyle | String | uuid | token风格, [参考:自定义Token风格](/up/token-style) | | dataRefreshPeriod | int | 30 | 默认数据持久组件实现类中,每次清理过期数据间隔的时间 (单位: 秒) ,默认值30秒,设置为-1代表不启动定时清理 | -| tokenSessionCheckLogin | Boolean | true | 获取 `Token-Session` 时是否必须登录 (如果配置为true,会在每次获取 `Token-Session` 时校验是否登录),[详解](/use/config?id=tokenSessionCheckLogin) | +| tokenSessionCheckLogin | Boolean | true | 获取 `Token-Session` 时是否必须登录 (如果配置为true,会在每次获取 `Token-Session` 时校验是否登录),[详解](/use/config?id=配置项详解:tokenSessionCheckLogin) | | autoRenew | Boolean | true | 是否打开自动续签 (如果此值为true, 框架会在每次直接或间接调用 `getLoginId()` 时进行一次过期检查与续签操作),[参考:token有效期详解](/fun/token-timeout) | | tokenPrefix | String | null | token前缀,例如填写 `Bearer` 实际传参 `satoken: Bearer xxxx-xxxx-xxxx-xxxx` [参考:自定义Token前缀](/up/token-prefix) | | isPrint | Boolean | true | 是否在初始化配置时打印版本字符画 | @@ -121,7 +121,7 @@ Server 端: | ticketTimeout | long | 300 | ticket 有效期 (单位: 秒) | | allowUrl | String | * | 所有允许的授权回调地址,多个用逗号隔开(不在此列表中的URL将禁止下放ticket),参考:[SSO整合:配置域名校验](/sso/sso-check-domain) | | isSlo | Boolean | false | 是否打开单点注销功能 | -| isHttp | Boolean | false | 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo),参考:[详解](/use/config?id=isHttp) | +| isHttp | Boolean | false | 是否打开模式三(此值为 true 时将使用 http 请求:校验 ticket 值、单点注销、获取 userinfo),参考:[详解](/use/config?id=配置项详解:isHttp) | | secretkey | String | null | 调用秘钥 (用于SSO模式三单点注销的接口通信身份校验) | @@ -131,12 +131,14 @@ Client 端: | :-------- | :-------- | :-------- | :-------- | | authUrl | String | null | 配置 Server 端单点登录授权地址 | | isSlo | Boolean | false | 是否打开单点注销功能 | -| isHttp | Boolean | false | 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo),参考:[详解](/use/config?id=isHttp) | -| checkTicketUrl| String | null | 配置 Server 端的 ticket 校验地址 | -| userinfoUrl | String | null | 配置 Server 端查询 userinfo 地址 | +| isHttp | Boolean | false | 是否打开模式三(此值为 true 时将使用 http 请求:校验 ticket 值、单点注销、获取 userinfo),参考:[详解](/use/config?id=配置项详解:isHttp) | +| checkTicketUrl| String | null | 配置 Server 端的 `ticket` 校验地址 | +| userinfoUrl | String | null | 配置 Server 端查询 `userinfo` 地址 | | sloUrl | String | null | 配置 Server 端单点注销地址 | | ssoLogoutCall | String | null | 配置当前 Client 端的单点注销回调URL (为空时自动获取) | | secretkey | String | null | 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验) | +| serverUrl | String | null | 配置 Server 端主机总地址,拼接在 `authUrl`、`checkTicketUrl`、`userinfoUrl`、`sloUrl` 属性前面,用以简化各种 url 配置,[详解](/use/config?id=配置项详解:serverUrl) | + 配置示例: ``` yml @@ -188,7 +190,7 @@ sa-token: | isImplicit | Boolean | false | 单独配置此 Client 是否打开模式:隐藏式(`Implicit`) | | isPassword | Boolean | false | 单独配置此 Client 是否打开模式:密码式(`Password`) | | isClient | Boolean | false | 单独配置此 Client 是否打开模式:凭证式(`Client Credentials`) | -| isAutoMode | Boolean | true | 是否自动判断此 Client 开放的授权模式。 参考:[详解](/use/config?id=isAutoMode) | +| isAutoMode | Boolean | true | 是否自动判断此 Client 开放的授权模式。 参考:[详解](/use/config?id=配置项详解:isAutoMode) | | isNewRefresh | Boolean | 取全局配置 | 单独配置此Client:是否在每次 `Refresh-Token` 刷新 `Access-Token` 时,产生一个新的 Refresh-Token [ 默认取全局配置 ] | | accessTokenTimeout | long | 取全局配置 | 单独配置此Client:`Access-Token` 保存的时间(单位:秒) [默认取全局配置] | | refreshTokenTimeout | long | 取全局配置 | 单独配置此Client:`Refresh-Token` 保存的时间(单位:秒) [默认取全局配置] | @@ -201,7 +203,7 @@ sa-token: 对部分配置项做一下详解 -#### maxLoginCount +#### 配置项详解:maxLoginCount 配置含义:同一账号最大登录数量。 @@ -214,7 +216,7 @@ sa-token: 假设一个账号的登录数量超过 `maxLoginCount` 后,将会主动注销第一个登录的会话(先进先出),以此保证队列中的有效会话数量始终 `<= maxLoginCount` 值。 -#### tokenSessionCheckLogin +#### 配置项详解:tokenSessionCheckLogin 配置含义:获取 `Token-Session` 时是否必须登录 (如果配置为true,会在每次获取 `Token-Session` 时校验是否登录)。 在调用 `StpUtil.login(id)` 登录后, @@ -236,7 +238,7 @@ sa-token: 但是 —— 有的场景下我们又确实需要在登录之前就使用 Token-Session 对象,这时候就把配置项 `tokenSessionCheckLogin` 值改为 `false` 即可。 -#### isAutoMode +#### 配置项详解:isAutoMode 配置含义:是否自动判断此 Client 开放的授权模式。 @@ -244,7 +246,7 @@ sa-token: - 此值为 false 时:四种模式(`isCode、isImplicit、isPassword、isClient`)是否生效,依靠局部配置+全局配置(两个都为 true 时才打开) -#### isHttp +#### 配置项详解:isHttp 配置含义:是否打开单点登录模式三。 @@ -252,3 +254,48 @@ sa-token: - 此配置项为 true 时,代表使用SSO模式三:使用 Http 请求校验 ticket 值、使用 Http 请求做到单点注销、使用 Http 请求同步 Userinfo 数据。 +#### 配置项详解:serverUrl + +配置含义:配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置。 + +在开发 SSO 模块时,我们需要在 sso-client 配置认证中心的各种地址,特别是在模式三下,一般代码会变成这样: + +``` java +sa-token: + sso: + # SSO-Server端 统一认证地址 + auth-url: http://sa-sso-server.com:9000/sso/auth + # 使用Http请求校验ticket + is-http: true + # SSO-Server端 ticket校验地址 + check-ticket-url: http://sa-sso-server.com:9000/sso/checkTicket + # 单点注销地址 + slo-url: http://sa-sso-server.com:9000/sso/logout + # 接口调用秘钥 + secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor + # SSO-Server端 查询userinfo地址 + userinfo-url: http://sa-sso-server.com:9000/sso/userinfo +``` + +一堆 xxx-url 配置比较繁琐,且含有大量重复字符,现在我们可以将其简化为: +``` java +sa-token: + sso: + server-url: http://sa-sso-server.com:9000 + is-http: true + secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor +``` + +只要你配置了 `server-url` 地址,Sa-Token 就可以自动拼接出其它四个地址: + +**例1,使用 server-url 简化:** +- 你配置的 server-url 值是:`http://sa-sso-server.com:9000`。 +- 框架拼接出的 auth-url 值就是:`http://sa-sso-server.com:9000/sso/auth`,其它三个 url 配置项同理。 + +**例2,使用 server-url + auth-url 简化:** +- 你配置的 server-url 值是:`http://sa-sso-server.com:9000`,auth-url 是:`/sso/auth2`。 +- 框架拼接出的 auth-url 值就是:`http://sa-sso-server.com:9000/sso/auth2`,其它三个 url 配置项同理。 + +**例3,auth-url 地址以 http 字符开头:** +- 你配置的 server-url 值是:`http://sa-sso-server.com:9000`,auth-url 是:`http://my-site.com/sso/auth2`。 +- 此时框架只以 auth-url 值为准,得到的 auth-url 值是:`http://my-site.com/sso/auth2`,其它三个 url 配置项同理。 diff --git a/sa-token-doc/doc/use/login-auth.md b/sa-token-doc/doc/use/login-auth.md index e67c636a..dfae5c00 100644 --- a/sa-token-doc/doc/use/login-auth.md +++ b/sa-token-doc/doc/use/login-auth.md @@ -63,7 +63,7 @@ public SaResult doLogin(String name, String pwd) { 如果你对 Cookie 功能还不太了解,也不用担心,我们会在之后的 [ 前后端分离 ] 章节中详细的阐述 Cookie 功能,现在你只需要了解最基本的两点: - Cookie 可以从后端控制往浏览器中写入 Token 值。 -- Cookie 会在每次请求时自动提交 Token 值。 +- Cookie 会在前端每次发起请求时自动提交 Token 值。 因此,在 Cookie 功能的加持下,我们可以仅靠 `StpUtil.login(id)` 一句代码就完成登录认证。 From af38a196c72f9053f9f62abe67010c8659f22a64 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 22 Aug 2022 09:23:11 +0800 Subject: [PATCH 129/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=20SaInterceptor=20?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/use/at-check.md | 38 +++++++++++++++++-- sa-token-doc/doc/use/route-check.md | 58 +++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 16 deletions(-) diff --git a/sa-token-doc/doc/use/at-check.md b/sa-token-doc/doc/use/at-check.md index af26b14e..82ae9e0b 100644 --- a/sa-token-doc/doc/use/at-check.md +++ b/sa-token-doc/doc/use/at-check.md @@ -10,6 +10,7 @@ - `@SaCheckPermission("user:add")`: 权限认证 —— 必须具有指定权限才能进入该方法。 - `@SaCheckSafe`: 二级认证校验 —— 必须二级认证之后才能进入该方法。 - `@SaCheckBasic`: HttpBasic认证 —— 只有通过 Basic 认证后才能进入该方法。 +- `@SaIgnore`:忽略认证 —— 表示被修饰的方法或类无需进行注解认证和路由拦截认证。 Sa-Token 使用全局拦截器完成注解鉴权功能,为了不为项目带来不必要的性能负担,拦截器默认处于关闭状态
因此,为了使用注解鉴权,**你必须手动将 Sa-Token 的全局拦截器注册到你项目中** @@ -24,11 +25,11 @@ Sa-Token 使用全局拦截器完成注解鉴权功能,为了不为项目带 ``` java @Configuration public class SaTokenConfigure implements WebMvcConfigurer { - // 注册Sa-Token的注解拦截器,打开注解式鉴权功能 + // 注册 Sa-Token 拦截器,打开注解式鉴权功能 @Override public void addInterceptors(InterceptorRegistry registry) { - // 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关) - registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**"); + // 注册 Sa-Token 拦截器,打开注解式鉴权功能 + registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); } } ``` @@ -114,7 +115,36 @@ orRole 字段代表权限认证未通过时的次要选择,两者只要其一 - 写法三:`orRole = {"admin, manager, staff"}`,代表必须同时具有三个角色。 -### 5、在业务逻辑层使用注解鉴权 +### 5、忽略认证 + +使用 `@SaIgnore` 可表示一个接口忽略认证: + +``` java +@SaCheckLogin +@RestController +public class TestController { + + // ... 其它方法 + + // 此接口加上了 @SaIgnore 可以游客访问 + @SaIgnore + @RequestMapping("getList") + public SaResult getList() { + // ... + return SaResult.ok(); + } +} +``` + +如上代码表示:`TestController` 中的所有方法都需要登录后才可以访问,但是 `getList` 接口可以匿名游客访问。 + +- @SaIgnore 修饰方法时代表这个方法可以被游客访问,修饰类时代表这个类中的所有接口都可以游客访问。 +- @SaIgnore 具有最高优先级,当 @SaIgnore 和其它鉴权注解一起出现时,其它鉴权注解都将被忽略。 +- @SaIgnore 同样可以忽略掉 Sa-Token 拦截器中的路由鉴权,在下面的 [路由拦截鉴权] 章节中我们会讲到。 + + + +### 6、在业务逻辑层使用注解鉴权 疑问:我能否将注解写在其它架构层呢,比如业务逻辑层? 使用拦截器模式,只能在`Controller层`进行注解鉴权,如需在任意层级使用注解鉴权,请参考:[AOP注解鉴权](/plugin/aop-at) diff --git a/sa-token-doc/doc/use/route-check.md b/sa-token-doc/doc/use/route-check.md index a1ab0996..5928ea15 100644 --- a/sa-token-doc/doc/use/route-check.md +++ b/sa-token-doc/doc/use/route-check.md @@ -18,28 +18,29 @@ public class SaTokenConfigure implements WebMvcConfigurer { // 注册拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { - // 注册 Sa-Token 的路由拦截器 - registry.addInterceptor(new SaRouteInterceptor()) - .addPathPatterns("/**") - .excludePathPatterns("/user/doLogin"); + // 注册 Sa-Token 拦截器,校验规则为 StpUtil.checkLogin() 登录校验。 + registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin())) + .addPathPatterns("/**") + .excludePathPatterns("/user/doLogin"); } } ``` -以上代码,我们注册了一个登录认证拦截器,并且排除了`/user/doLogin`接口用来开放登录(除了`/user/doLogin`以外的所有接口都需要登录才能访问)。 +以上代码,我们注册了一个基于 `StpUtil.checkLogin()` 的登录校验拦截器,并且排除了`/user/doLogin`接口用来开放登录(除了`/user/doLogin`以外的所有接口都需要登录才能访问)。 +!> `SaInterceptor` 是新版本提供的拦截器,点此 [查看旧版本代码迁移示例](https://blog.csdn.net/shengzhang_/article/details/126458949)。 ### 2、校验函数详解 -自定义认证规则:`new SaRouteInterceptor()` 是最简单的无参构造写法,代表只进行默认的登录校验功能。 +自定义认证规则:`new SaInterceptor(handle -> StpUtil.checkLogin())` 是最简单的写法,代表只进行登录校验功能。 -我们可以往构造函数塞一个 lambda 表达式,来自定义认证规则,例如: +我们可以往构造函数塞一个完整的 lambda 表达式,来定义详细的校验规则,例如: ``` java @Configuration public class SaTokenConfigure implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { - // 注册 Sa-Token 的路由拦截器,自定义认证规则 - registry.addInterceptor(new SaRouteInterceptor((req, res, handler)->{ + // 注册 Sa-Token 拦截器,定义详细认证规则 + registry.addInterceptor(new SaInterceptor(handler -> { // 根据路由划分模块,不同模块不同鉴权 SaRouter.match("/user/**", r -> StpUtil.checkPermission("user")); SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin")); @@ -61,11 +62,11 @@ SaRouter.match() 匹配函数有两个参数: ``` java @Configuration public class SaTokenConfigure implements WebMvcConfigurer { - // 注册Sa-Token的拦截器 + // 注册 Sa-Token 的拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { // 注册路由拦截器,自定义认证规则 - registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> { + registry.addInterceptor(new SaInterceptor((req, res, handler) -> { // 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录 SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin()); @@ -140,7 +141,7 @@ SaRouter 使用 `SaRouter.stop()` 可以提前退出匹配链,例: ``` java -registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> { +registry.addInterceptor(new SaInterceptor((req, res, handler) -> { SaRouter.match("/**").check(r -> System.out.println("进入1")); SaRouter.match("/**").check(r -> System.out.println("进入2")).stop(); SaRouter.match("/**").check(r -> System.out.println("进入3")); @@ -176,3 +177,36 @@ SaRouter.match("/**").check(/* --- */); free() 的作用是:打开一个独立的作用域,使内部的 stop() 不再一次性跳出整个 Auth 函数,而是仅仅跳出当前 free 作用域。 + +### 6、使用注解忽略掉路由拦截校验 + +我们可以使用 `@SaIgnore` 注解,忽略掉路由拦截认证: + +1、先配置好了拦截规则: +``` java +@Override +public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new SaInterceptor(handler -> { + // 根据路由划分模块,不同模块不同鉴权 + SaRouter.match("/user/**", r -> StpUtil.checkPermission("user")); + SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin")); + SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods")); + // ... + })).addPathPatterns("/**"); +} +``` + +2、然后在 `Controller` 里又添加了忽略校验的注解 +``` java +@SaIgnore +@RequestMapping("/user/getList") +public SaResult getList() { + System.out.println("------------ 访问进来方法"); + return SaResult.ok(); +} +``` + +请求将会跳过拦截器的校验,直接进入 Controller 的方法中。 + +**注意点:此注解的忽略效果只针对 SaInterceptor拦截器 和 APO注解鉴权 生效,对自定义拦截器与过滤器不生效。** + From 731e91050c82b7b01664d86d95ef2c9b03d92449 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 22 Aug 2022 09:24:01 +0800 Subject: [PATCH 130/144] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=8B=E8=81=94?= =?UTF-8?q?=EF=BC=9Ahippo4j?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ sa-token-doc/index.html | 3 +++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 6f9c1dcc..154dc166 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,8 @@ Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) - [[ TLog ]](https://gitee.com/dromara/TLog):一个轻量级的分布式日志标记追踪神器 +- [[ hippo4j ]](https://gitee.com/agentart/hippo4j):强大的动态线程池框架,附带监控报警功能 + ## 交流群 diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 243a5e58..c66b4a8a 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -444,6 +444,9 @@ + + +
From 0c1588daa803febf092f521eae64579b6d5c2b16 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 22 Aug 2022 16:29:42 +0800 Subject: [PATCH 131/144] =?UTF-8?q?`sa-token-jwt`=20=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E6=94=B9=E4=B8=BA=20`hutool-jwt`=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E5=8D=87=E7=BA=A7=E7=89=88=E6=9C=AC=E4=B8=BA=205.8.5?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-plugin/sa-token-jwt/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sa-token-plugin/sa-token-jwt/pom.xml b/sa-token-plugin/sa-token-jwt/pom.xml index f5bb8a20..bdaf04ef 100644 --- a/sa-token-plugin/sa-token-jwt/pom.xml +++ b/sa-token-plugin/sa-token-jwt/pom.xml @@ -26,8 +26,8 @@ cn.hutool - hutool-all - 5.7.14 + hutool-jwt + 5.8.5
From 0a7fb4dd5e7c9e5800568a6bf5801e85ddbeeb67 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 22 Aug 2022 16:30:12 +0800 Subject: [PATCH 132/144] =?UTF-8?q?`sa-token-jwt`=20=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=20`Util=20+=20Template`=20=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E6=96=B9=E4=BE=BF=E9=92=88=E5=AF=B9=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=87=8D=E5=86=99=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/plugin/jwt-extend.md | 19 ++ .../cn/dev33/satoken/jwt/SaJwtTemplate.java | 274 ++++++++++++++++++ .../java/cn/dev33/satoken/jwt/SaJwtUtil.java | 181 +++--------- 3 files changed, 341 insertions(+), 133 deletions(-) create mode 100644 sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtTemplate.java diff --git a/sa-token-doc/doc/plugin/jwt-extend.md b/sa-token-doc/doc/plugin/jwt-extend.md index 358ed480..acc0b114 100644 --- a/sa-token-doc/doc/plugin/jwt-extend.md +++ b/sa-token-doc/doc/plugin/jwt-extend.md @@ -176,3 +176,22 @@ public void setUserStpLogic() { +### 8、自定义 SaJwtUtil 生成 token 的算法 + +如果需要自定义生成 token 的算法(例如更换sign方式),直接重写 SaJwtTemplate 对象即可: + +``` java +/** + * 自定义 SaJwtUtil 生成 token 的算法 + */ +@Autowired +public void setSaJwtTemplate() { + SaJwtUtil.setSaJwtTemplate(new SaJwtTemplate() { + @Override + public String generateToken(JWT jwt, String keyt) { + System.out.println("------ 自定义了 token 生成算法"); + return super.generateToken(jwt, keyt); + } + }); +} +``` diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtTemplate.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtTemplate.java new file mode 100644 index 00000000..92bca566 --- /dev/null +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtTemplate.java @@ -0,0 +1,274 @@ +package cn.dev33.satoken.jwt; + +import java.util.Map; +import java.util.Objects; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.jwt.exception.SaJwtException; +import cn.dev33.satoken.jwt.exception.SaJwtExceptionCode; +import cn.dev33.satoken.util.SaFoxUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.jwt.JWT; +import cn.hutool.jwt.JWTException; + +/** + * jwt 操作模板方法封装 + * @author kong + * + */ +public class SaJwtTemplate { + + /** + * key:账号类型 + */ + public static final String LOGIN_TYPE = "loginType"; + + /** + * key:账号id + */ + public static final String LOGIN_ID = "loginId"; + + /** + * key:登录设备类型 + */ + public static final String DEVICE = "device"; + + /** + * key:有效截止期 (时间戳) + */ + public static final String EFF = "eff"; + + /** + * key:乱数 ( 混入随机字符串,防止每次生成的 token 都是一样的 ) + */ + public static final String RN_STR = "rnStr"; + + /** + * 当有效期被设为此值时,代表永不过期 + */ + public static final long NEVER_EXPIRE = SaTokenDao.NEVER_EXPIRE; + + /** + * 表示一个值不存在 + */ + public static final long NOT_VALUE_EXPIRE = SaTokenDao.NOT_VALUE_EXPIRE; + + // ------ 创建 + + /** + * 创建 jwt (简单方式) + * @param loginType 登录类型 + * @param loginId 账号id + * @param extraData 扩展数据 + * @param keyt 秘钥 + * @return jwt-token + */ + public String createToken(String loginType, Object loginId, Map extraData, String keyt) { + + // 构建 + JWT jwt = JWT.create() + .setPayload(LOGIN_TYPE, loginType) + .setPayload(LOGIN_ID, loginId) + .setPayload(RN_STR, SaFoxUtil.getRandomString(32)) + .addPayloads(extraData) + ; + + // 返回 + return generateToken(jwt, keyt); + } + + /** + * 创建 jwt (全参数方式) + * @param loginType 账号类型 + * @param loginId 账号id + * @param device 设备类型 + * @param timeout token有效期 (单位 秒) + * @param extraData 扩展数据 + * @param keyt 秘钥 + * @return jwt-token + */ + public String createToken(String loginType, Object loginId, String device, + long timeout, Map extraData, String keyt) { + + // 计算有效期 + long effTime = timeout; + if(timeout != NEVER_EXPIRE) { + effTime = timeout * 1000 + System.currentTimeMillis(); + } + + // 创建 + JWT jwt = JWT.create() + .setPayload(LOGIN_TYPE, loginType) + .setPayload(LOGIN_ID, loginId) + .setPayload(DEVICE, device) + .setPayload(EFF, effTime) + .setPayload(RN_STR, SaFoxUtil.getRandomString(32)) + .addPayloads(extraData); + + // 返回 + return generateToken(jwt, keyt); + } + + /** + * 为 JWT 对象和 keyt 秘钥,生成 token 字符串 + * @param jwt JWT构建对象 + * @return 根据 JWT 对象和 keyt 秘钥,生成的 token 字符串 + */ + public String generateToken (JWT jwt, String keyt) { + return jwt.setKey(keyt.getBytes()).sign(); + } + + // ------ 解析 + + /** + * jwt 解析 + * @param token Jwt-Token值 + * @param loginType 登录类型 + * @param keyt 秘钥 + * @param isCheckTimeout 是否校验 timeout 字段 + * @return 解析后的jwt 对象 + */ + public JWT parseToken(String token, String loginType, String keyt, boolean isCheckTimeout) { + + // 秘钥不可以为空 + if(keyt == null) { + throw new SaJwtException("请配置 jwt 秘钥"); + } + + // 如果token为null + if(token == null) { + throw new SaJwtException("jwt 字符串不可为空"); + } + + // 解析 + JWT jwt = null; + try { + jwt = JWT.of(token); + } catch (JWTException e) { + throw new SaJwtException("jwt 解析失败:" + token, e).setCode(SaJwtExceptionCode.CODE_40101); + } + JSONObject payloads = jwt.getPayloads(); + + // 校验 Token 签名 + boolean verify = jwt.setKey(keyt.getBytes()).verify(); + if(verify == false) { + throw new SaJwtException("jwt 签名无效:" + token).setCode(SaJwtExceptionCode.CODE_40102); + }; + + // 校验 loginType + if(Objects.equals(loginType, payloads.getStr(LOGIN_TYPE)) == false) { + throw new SaJwtException("jwt loginType 无效:" + token).setCode(SaJwtExceptionCode.CODE_40103); + } + + // 校验 Token 有效期 + if(isCheckTimeout) { + Long effTime = payloads.getLong(EFF, 0L); + if(effTime != NEVER_EXPIRE) { + if(effTime == null || effTime < System.currentTimeMillis()) { + throw new SaJwtException("jwt 已过期:" + token).setCode(SaJwtExceptionCode.CODE_40104); + } + } + } + + // 返回 + return jwt; + } + + /** + * 获取 jwt 数据载荷 (校验 sign、loginType、timeout) + * @param token token值 + * @param loginType 登录类型 + * @param keyt 秘钥 + * @return 载荷 + */ + public JSONObject getPayloads(String token, String loginType, String keyt) { + return parseToken(token, loginType, keyt, true).getPayloads(); + } + + /** + * 获取 jwt 数据载荷 (校验 sign、loginType,不校验 timeout) + * @param token token值 + * @param loginType 登录类型 + * @param keyt 秘钥 + * @return 载荷 + */ + public JSONObject getPayloadsNotCheck(String token, String loginType, String keyt) { + return parseToken(token, loginType, keyt, false).getPayloads(); + } + + /** + * 获取 jwt 代表的账号id + * @param token Token值 + * @param loginType 登录类型 + * @param keyt 秘钥 + * @return 值 + */ + public Object getLoginId(String token, String loginType, String keyt) { + return getPayloads(token, loginType, keyt).get(LOGIN_ID); + } + + /** + * 获取 jwt 代表的账号id (未登录时返回null) + * @param token Token值 + * @param loginType 登录类型 + * @param keyt 秘钥 + * @return 值 + */ + public Object getLoginIdOrNull(String token, String loginType, String keyt) { + try { + return getPayloads(token, loginType, keyt).get(LOGIN_ID); + } catch (SaJwtException e) { + return null; + } + } + + /** + * 获取 jwt 剩余有效期 + * @param token JwtToken值 + * @param loginType 登录类型 + * @param keyt 秘钥 + * @return 值 + */ + public long getTimeout(String token, String loginType, String keyt) { + + // 如果token为null + if(token == null) { + return NOT_VALUE_EXPIRE; + } + + // 取出数据 + JWT jwt = null; + try { + jwt = JWT.of(token); + } catch (JWTException e) { + // 解析失败 + return NOT_VALUE_EXPIRE; + } + JSONObject payloads = jwt.getPayloads(); + + // 如果签名无效 + boolean verify = jwt.setKey(keyt.getBytes()).verify(); + if(verify == false) { + return NOT_VALUE_EXPIRE; + }; + + // 如果 loginType 无效 + if(Objects.equals(loginType, payloads.getStr(LOGIN_TYPE)) == false) { + return NOT_VALUE_EXPIRE; + } + + // 如果被设置为:永不过期 + Long effTime = payloads.get(EFF, Long.class); + if(effTime == NEVER_EXPIRE) { + return NEVER_EXPIRE; + } + // 如果已经超时 + if(effTime == null || effTime < System.currentTimeMillis()) { + return NOT_VALUE_EXPIRE; + } + + // 计算timeout (转化为以秒为单位的有效时间) + return (effTime - System.currentTimeMillis()) / 1000; + } + +} diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtUtil.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtUtil.java index d2bcc75f..a49ca8c1 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtUtil.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtUtil.java @@ -1,15 +1,9 @@ package cn.dev33.satoken.jwt; import java.util.Map; -import java.util.Objects; -import cn.dev33.satoken.dao.SaTokenDao; -import cn.dev33.satoken.jwt.exception.SaJwtException; -import cn.dev33.satoken.jwt.exception.SaJwtExceptionCode; -import cn.dev33.satoken.util.SaFoxUtil; import cn.hutool.json.JSONObject; import cn.hutool.jwt.JWT; -import cn.hutool.jwt.JWTException; /** * jwt 操作工具类封装 @@ -18,40 +12,64 @@ import cn.hutool.jwt.JWTException; */ public class SaJwtUtil { + /** + * 底层 saJwtTemplate 对象 + */ + public static SaJwtTemplate saJwtTemplate = new SaJwtTemplate(); + + /** + * 获取底层 saJwtTemplate 对象 + * @return / + */ + public static SaJwtTemplate getSaJwtTemplate() { + return saJwtTemplate; + } + + /** + * 设置底层 saJwtTemplate 对象 + * @param saJwtTemplate / + */ + public static void setSaJwtTemplate(SaJwtTemplate saJwtTemplate) { + SaJwtUtil.saJwtTemplate = saJwtTemplate; + } + + // 常量 + + /** * key:账号类型 */ - public static final String LOGIN_TYPE = "loginType"; + public static final String LOGIN_TYPE = SaJwtTemplate.LOGIN_TYPE; /** * key:账号id */ - public static final String LOGIN_ID = "loginId"; + public static final String LOGIN_ID = SaJwtTemplate.LOGIN_ID; /** * key:登录设备类型 */ - public static final String DEVICE = "device"; + public static final String DEVICE = SaJwtTemplate.DEVICE; /** * key:有效截止期 (时间戳) */ - public static final String EFF = "eff"; + public static final String EFF = SaJwtTemplate.EFF; /** * key:乱数 ( 混入随机字符串,防止每次生成的 token 都是一样的 ) */ - public static final String RN_STR = "rnStr"; + public static final String RN_STR = SaJwtTemplate.RN_STR; /** * 当有效期被设为此值时,代表永不过期 */ - public static final long NEVER_EXPIRE = SaTokenDao.NEVER_EXPIRE; + public static final long NEVER_EXPIRE = SaJwtTemplate.NEVER_EXPIRE; /** * 表示一个值不存在 */ - public static final long NOT_VALUE_EXPIRE = SaTokenDao.NOT_VALUE_EXPIRE; + public static final long NOT_VALUE_EXPIRE = SaJwtTemplate.NOT_VALUE_EXPIRE; // ------ 创建 @@ -64,18 +82,7 @@ public class SaJwtUtil { * @return jwt-token */ public static String createToken(String loginType, Object loginId, Map extraData, String keyt) { - - // 构建 - String token = JWT.create() - .setPayload(LOGIN_TYPE, loginType) - .setPayload(LOGIN_ID, loginId) - .setPayload(RN_STR, SaFoxUtil.getRandomString(32)) - .addPayloads(extraData) - .setKey(keyt.getBytes()) - .sign(); - - // 返回 - return token; + return saJwtTemplate.createToken(loginType, loginId, extraData, keyt); } /** @@ -90,26 +97,18 @@ public class SaJwtUtil { */ public static String createToken(String loginType, Object loginId, String device, long timeout, Map extraData, String keyt) { - - // 计算有效期 - long effTime = timeout; - if(timeout != NEVER_EXPIRE) { - effTime = timeout * 1000 + System.currentTimeMillis(); - } - - // 创建 - JWT jwt = JWT.create() - .setPayload(LOGIN_TYPE, loginType) - .setPayload(LOGIN_ID, loginId) - .setPayload(DEVICE, device) - .setPayload(EFF, effTime) - .setPayload(RN_STR, SaFoxUtil.getRandomString(32)) - .addPayloads(extraData); - - // 返回 - return jwt.setKey(keyt.getBytes()).sign(); + return saJwtTemplate.createToken(loginType, loginId, device, timeout, extraData, keyt); } + /** + * 为 JWT 对象和 keyt 秘钥,生成 token 字符串 + * @param jwt JWT构建对象 + * @return 根据 JWT 对象和 keyt 秘钥,生成的 token 字符串 + */ + public static String generateToken (JWT jwt, String keyt) { + return saJwtTemplate.generateToken(jwt, keyt); + } + // ------ 解析 /** @@ -121,49 +120,7 @@ public class SaJwtUtil { * @return 解析后的jwt 对象 */ public static JWT parseToken(String token, String loginType, String keyt, boolean isCheckTimeout) { - - // 秘钥不可以为空 - if(keyt == null) { - throw new SaJwtException("请配置 jwt 秘钥"); - } - - // 如果token为null - if(token == null) { - throw new SaJwtException("jwt 字符串不可为空"); - } - - // 解析 - JWT jwt = null; - try { - jwt = JWT.of(token); - } catch (JWTException e) { - throw new SaJwtException("jwt 解析失败:" + token, e).setCode(SaJwtExceptionCode.CODE_40101); - } - JSONObject payloads = jwt.getPayloads(); - - // 校验 Token 签名 - boolean verify = jwt.setKey(keyt.getBytes()).verify(); - if(verify == false) { - throw new SaJwtException("jwt 签名无效:" + token).setCode(SaJwtExceptionCode.CODE_40102); - }; - - // 校验 loginType - if(Objects.equals(loginType, payloads.getStr(LOGIN_TYPE)) == false) { - throw new SaJwtException("jwt loginType 无效:" + token).setCode(SaJwtExceptionCode.CODE_40103); - } - - // 校验 Token 有效期 - if(isCheckTimeout) { - Long effTime = payloads.getLong(EFF, 0L); - if(effTime != NEVER_EXPIRE) { - if(effTime == null || effTime < System.currentTimeMillis()) { - throw new SaJwtException("jwt 已过期:" + token).setCode(SaJwtExceptionCode.CODE_40104); - } - } - } - - // 返回 - return jwt; + return saJwtTemplate.parseToken(token, loginType, keyt, isCheckTimeout); } /** @@ -174,7 +131,7 @@ public class SaJwtUtil { * @return 载荷 */ public static JSONObject getPayloads(String token, String loginType, String keyt) { - return parseToken(token, loginType, keyt, true).getPayloads(); + return saJwtTemplate.getPayloads(token, loginType, keyt); } /** @@ -185,7 +142,7 @@ public class SaJwtUtil { * @return 载荷 */ public static JSONObject getPayloadsNotCheck(String token, String loginType, String keyt) { - return parseToken(token, loginType, keyt, false).getPayloads(); + return saJwtTemplate.getPayloadsNotCheck(token, loginType, keyt); } /** @@ -196,7 +153,7 @@ public class SaJwtUtil { * @return 值 */ public static Object getLoginId(String token, String loginType, String keyt) { - return getPayloads(token, loginType, keyt).get(LOGIN_ID); + return saJwtTemplate.getLoginId(token, loginType, keyt); } /** @@ -207,11 +164,7 @@ public class SaJwtUtil { * @return 值 */ public static Object getLoginIdOrNull(String token, String loginType, String keyt) { - try { - return getPayloads(token, loginType, keyt).get(LOGIN_ID); - } catch (SaJwtException e) { - return null; - } + return saJwtTemplate.getLoginIdOrNull(token, loginType, keyt); } /** @@ -222,45 +175,7 @@ public class SaJwtUtil { * @return 值 */ public static long getTimeout(String token, String loginType, String keyt) { - - // 如果token为null - if(token == null) { - return NOT_VALUE_EXPIRE; - } - - // 取出数据 - JWT jwt = null; - try { - jwt = JWT.of(token); - } catch (JWTException e) { - // 解析失败 - return NOT_VALUE_EXPIRE; - } - JSONObject payloads = jwt.getPayloads(); - - // 如果签名无效 - boolean verify = jwt.setKey(keyt.getBytes()).verify(); - if(verify == false) { - return NOT_VALUE_EXPIRE; - }; - - // 如果 loginType 无效 - if(Objects.equals(loginType, payloads.getStr(LOGIN_TYPE)) == false) { - return NOT_VALUE_EXPIRE; - } - - // 如果被设置为:永不过期 - Long effTime = payloads.get(EFF, Long.class); - if(effTime == NEVER_EXPIRE) { - return NEVER_EXPIRE; - } - // 如果已经超时 - if(effTime == null || effTime < System.currentTimeMillis()) { - return NOT_VALUE_EXPIRE; - } - - // 计算timeout (转化为以秒为单位的有效时间) - return (effTime - System.currentTimeMillis()) / 1000; + return saJwtTemplate.getTimeout(token, loginType, keyt); } } From 56e3b792dfcae9712309ed1fa046c8b3b4a4a546 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 22 Aug 2022 16:30:18 +0800 Subject: [PATCH 133/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/fun/three-scope.md | 2 +- sa-token-doc/doc/more/common-questions.md | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/sa-token-doc/doc/fun/three-scope.md b/sa-token-doc/doc/fun/three-scope.md index 6b4ebe8d..32320d3d 100644 --- a/sa-token-doc/doc/fun/three-scope.md +++ b/sa-token-doc/doc/fun/three-scope.md @@ -8,7 +8,7 @@ Sa-Token 数据存储有三大作用域,分别是: - `SaApplication` - 全局作用域:存储的数据在全局范围内有效。 -### SaStorage - 数据读写三大作用域 +### SaStorage - 请求作用域 在 SaStorage 中存储的数据只在一次请求范围内有效,请求结束后数据自动清除。使用 SaStorage 时无需处于登录状态。 ``` java diff --git a/sa-token-doc/doc/more/common-questions.md b/sa-token-doc/doc/more/common-questions.md index 965f6e9d..5a13c591 100644 --- a/sa-token-doc/doc/more/common-questions.md +++ b/sa-token-doc/doc/more/common-questions.md @@ -33,7 +33,6 @@ - 如果是 WebFlux 环境就引入 `sa-token-reactor-spring-boot-starter` 依赖,参考:[在WebFlux环境集成](/start/webflux-example) - 引入错误的依赖会导致`SaTokenContext`初始化失败,抛出上述异常 - 如果你还无法分辨你是哪个环境,就看你的 pom.xml 依赖,如果引入了`spring-boot-starter-web`就是SpringMVC环境,如果引入了 `spring-boot-starter-webflux` 就是WebFlux环境。……什么?你说你两个都引入了?那你的项目能启动成功吗? - - 你说你两个包都没引入?那你为什么不引入一个呢? 3. 如果是 WebFlux 环境而且正确引入了依赖,依然报错,请检查是否注册了全局过滤器,在 WebFlux 下这一步是必须的。 4. 如果以上步骤排除无误后依然报错,请直接提 issues 或者加入QQ群求助。 @@ -49,11 +48,9 @@ ### 加了注解进行鉴权认证,不生效? 1. 注解鉴权功能默认关闭,两种方式任选其一进行打开:注册注解拦截器、集成AOP模块,参考:[注解式鉴权](/use/at-check) 2. 在Spring环境中, 如果同时配置了`WebMvcConfigurer`和`WebMvcConfigurationSupport`时, 也会导致拦截器失效. - - **常见场景**: 很多项目中会在`WebMvcConfigurationSupport`中配置`addResourceHandlers`方法开放Swagger等相关静态资源映射, 同时基于Sa-Token添加了`WebMvcConfigurer`配置`addInterceptors`方法注册注解拦截器, 这样会导致注解拦截器失效. - - **解决方案**: `WebMvcConfigurer`和`WebMvcConfigurationSupport`只选一个配置, 建议统一通过实现`WebMvcConfigurer`接口进行配置. -4. 如果以上步骤处理后仍然没有效果,加群说明一下复现步骤 + - **常见场景**: 很多项目中会在`WebMvcConfigurationSupport`中配置`addResourceHandlers`方法开放Swagger等相关静态资源映射, 同时基于Sa-Token添加了`WebMvcConfigurer`配置`addInterceptors`方法注册注解拦截器, 这样会导致注解拦截器失效. + - **解决方案**: `WebMvcConfigurer`和`WebMvcConfigurationSupport`只选一个配置, 建议统一通过实现`WebMvcConfigurer`接口进行配置. +3. 如果以上步骤处理后仍然没有效果,加群说明一下复现步骤 ### 有时候我不加 Token 也可以通过鉴权,请问是怎么回事? From ef61a965b525f1310575183d6cbd54906c4657ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=94=E6=98=8E?= <2393584716@qq.com> Date: Mon, 22 Aug 2022 09:39:41 +0000 Subject: [PATCH 134/144] =?UTF-8?q?update=20README.md.=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=9F=A5=E8=AF=86=E6=98=9F=E7=90=83=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 孔明 <2393584716@qq.com> --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 154dc166..e4905d17 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,9 @@ Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) - [[ hippo4j ]](https://gitee.com/agentart/hippo4j):强大的动态线程池框架,附带监控报警功能 +### 知识星球 + + ## 交流群 QQ交流群:496757342 [点击加入](https://jq.qq.com/?_wv=1027&k=ceibbMFr) From b289f27dd2b0cd7f24ebdc70a8b7cecd3222668b Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 22 Aug 2022 17:40:50 +0800 Subject: [PATCH 135/144] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=93=BE=E6=8E=A5?= =?UTF-8?q?=EF=BC=9A=E7=9F=A5=E8=AF=86=E6=98=9F=E7=90=83.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e4905d17..1cdd7413 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) - [[ hippo4j ]](https://gitee.com/agentart/hippo4j):强大的动态线程池框架,附带监控报警功能 -### 知识星球 +## 知识星球 From 31462217b4ead2be099f7b5a74f1ce7087b1ef81 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 22 Aug 2022 18:10:53 +0800 Subject: [PATCH 136/144] =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=9F=A5=E8=AF=86=E6=98=9F=E7=90=83=E9=93=BE?= =?UTF-8?q?=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/index.html | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index c66b4a8a..455089aa 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -484,11 +484,17 @@
+

Dromara 知识星球

+
+ +
+
+ @@ -565,7 +571,7 @@ // 点击二维码放大 $('.wx-qr,.dro-qr').click(function() { var w = '300px'; - var h = '300px'; + var h = 'auto'; var content = '
' + '' + '
'; From 9d6ce502c1680334b8a2e9ce9e68d97f8fffb49e Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 23 Aug 2022 16:43:17 +0800 Subject: [PATCH 137/144] =?UTF-8?q?Sa-OAuth2=20=E6=A8=A1=E5=9D=97=E5=AF=86?= =?UTF-8?q?=E7=A0=81=E5=BC=8F=E6=96=B0=E5=A2=9E=20client=5Fsecret=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pj/oauth2/SaOAuthClientController.java | 1 + .../src/main/resources/templates/index.html | 2 +- .../satoken/oauth2/logic/SaOAuth2Handle.java | 15 ++++++++------- .../oauth2/logic/SaOAuth2Template.java | 19 +++++++++++++++++++ .../satoken/oauth2/logic/SaOAuth2Util.java | 11 +++++++++++ 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/oauth2/SaOAuthClientController.java b/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/oauth2/SaOAuthClientController.java index e0cb545e..aed42c2a 100644 --- a/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/oauth2/SaOAuthClientController.java +++ b/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/oauth2/SaOAuthClientController.java @@ -94,6 +94,7 @@ public class SaOAuthClientController { String str = OkHttps.sync(serverUrl + "/oauth2/token") .addBodyPara("grant_type", "password") .addBodyPara("client_id", clientId) + .addBodyPara("client_secret", clientSecret) .addBodyPara("username", username) .addBodyPara("password", password) .post() diff --git a/sa-token-demo/sa-token-demo-oauth2-client/src/main/resources/templates/index.html b/sa-token-demo/sa-token-demo-oauth2-client/src/main/resources/templates/index.html index ee520f89..9d5b3121 100644 --- a/sa-token-demo/sa-token-demo-oauth2-client/src/main/resources/templates/index.html +++ b/sa-token-demo/sa-token-demo-oauth2-client/src/main/resources/templates/index.html @@ -76,7 +76,7 @@ 账号: 密码: - http://sa-oauth-server.com:8001/oauth2/token?grant_type=password&client_id={value}&username={value}&password={value} + http://sa-oauth-server.com:8001/oauth2/token?grant_type=password&client_id={value}&client_secret={value}&username={value}&password={value}

模式四:凭证式(Client Credentials)

diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java index ca323660..97413b8b 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java @@ -255,30 +255,31 @@ public class SaOAuth2Handle { String username = req.getParamNotNull(Param.username); String password = req.getParamNotNull(Param.password); String clientId = req.getParamNotNull(Param.client_id); + String clientSecret = req.getParamNotNull(Param.client_secret); String scope = req.getParam(Param.scope, ""); - // 2、校验 ClientScope - SaOAuth2Util.checkContract(clientId, scope); + // 2、校验 ClientScope 和 scope + SaOAuth2Util.checkClientSecretAndScope(clientId, clientSecret, scope); // 3、防止因前端误传token造成逻辑干扰 - SaHolder.getStorage().set(StpUtil.stpLogic.splicingKeyJustCreatedSave(), "no-token"); + // SaHolder.getStorage().set(StpUtil.stpLogic.splicingKeyJustCreatedSave(), "no-token"); - // 4、调用API 开始登录,如果没能成功登录,则直接退出 + // 3、调用API 开始登录,如果没能成功登录,则直接退出 Object retObj = cfg.getDoLoginHandle().apply(username, password); if(StpUtil.isLogin() == false) { return retObj; } - // 5、构建 ra对象 + // 4、构建 ra对象 RequestAuthModel ra = new RequestAuthModel(); ra.clientId = clientId; ra.loginId = StpUtil.getLoginId(); ra.scope = scope; - // 7、生成 Access-Token + // 5、生成 Access-Token AccessTokenModel at = SaOAuth2Util.generateAccessToken(ra, true); - // 8、返回 Access-Token + // 6、返回 Access-Token return SaResult.data(at.toLineMap()); } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java index 16bdcf83..c602a9c0 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java @@ -396,6 +396,25 @@ public class SaOAuth2Template { SaOAuth2Exception.throwBy(cm.clientSecret == null || cm.clientSecret.equals(clientSecret) == false, "无效client_secret: " + clientSecret); return cm; } + /** + * 校验:clientId 与 clientSecret 是否正确,并且是否签约了指定 scopes + * @param clientId 应用id + * @param clientSecret 秘钥 + * @param scopes 权限(多个用逗号隔开) + * @return SaClientModel对象 + */ + public SaClientModel checkClientSecretAndScope(String clientId, String clientSecret, String scopes) { + // 先校验 clientSecret + SaClientModel cm = checkClientSecret(clientId, clientSecret); + // 再校验 是否签约 + List clientScopeList = SaFoxUtil.convertStringToList(cm.contractScope); + List scopelist = SaFoxUtil.convertStringToList(scopes); + if(clientScopeList.containsAll(scopelist) == false) { + throw new SaOAuth2Exception("请求的Scope暂未签约"); + } + // 返回数据 + return cm; + } /** * 校验:使用 code 获取 token 时提供的参数校验 * @param code 授权码 diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java index 25004650..3c4acad4 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java @@ -207,6 +207,17 @@ public class SaOAuth2Util { return saOAuth2Template.checkClientSecret(clientId, clientSecret); } + /** + * 校验:clientId 与 clientSecret 是否正确,并且是否签约了指定 scopes + * @param clientId 应用id + * @param clientSecret 秘钥 + * @param scopes 权限(多个用逗号隔开) + * @return SaClientModel对象 + */ + public static SaClientModel checkClientSecretAndScope(String clientId, String clientSecret, String scopes) { + return saOAuth2Template.checkClientSecretAndScope(clientId, clientSecret, scopes); + } + /** * 校验:使用 code 获取 token 时提供的参数校验 * @param code 授权码 From 1fe63a82f9764e63737938dada7d9521be1032ef Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 23 Aug 2022 16:44:52 +0800 Subject: [PATCH 138/144] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=9F=A5=E8=AF=86?= =?UTF-8?q?=E6=98=9F=E7=90=83=E5=B1=95=E7=A4=BA=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/index.html | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 455089aa..46cac0c6 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -412,8 +412,12 @@

为往圣继绝学,一个人或许能走的更快,但一群人会走的更远。

+
+

Dromara 知识星球

+ +
-
+
@@ -483,18 +487,18 @@
  • 联系:暂无
  • -
    + +

    Sa-Token 公众号

    -
    --> +
    From 05c87274410fd825ff3c5b864ef2dd5103f9a8ef Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 23 Aug 2022 16:46:22 +0800 Subject: [PATCH 139/144] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/doc/oauth2/oauth2-api.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sa-token-doc/doc/oauth2/oauth2-api.md b/sa-token-doc/doc/oauth2/oauth2-api.md index 52009a9a..a214c271 100644 --- a/sa-token-doc/doc/oauth2/oauth2-api.md +++ b/sa-token-doc/doc/oauth2/oauth2-api.md @@ -189,19 +189,21 @@ redirect_uri#token=xxxx-xxxx-xxxx-xxxx http://sa-oauth-server.com:8001/oauth2/token ?grant_type=password &client_id={value} + &client_secret={value} &username={value} &password={value} ``` 参数详解: -| 参数 | 是否必填 | 说明 | -| :-------- | :-------- | :-------- | -| grant_type| 是 | 返回类型,这里请填写:password| -| client_id | 是 | 应用id | -| username | 是 | 用户的Server端账号 | -| password | 是 | 用户的Server端密码 | -| scope | 否 | 具体请求的权限,多个用逗号隔开 | +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| grant_type | 是 | 返回类型,这里请填写:password| +| client_id | 是 | 应用id | +| client_secret | 是 | 应用秘钥 | +| username | 是 | 用户的Server端账号 | +| password | 是 | 用户的Server端密码 | +| scope | 否 | 具体请求的权限,多个用逗号隔开 | 接口返回示例: From bb429ab0d9fc80c693f021b84804d81e0e3fc230 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 24 Aug 2022 13:10:18 +0800 Subject: [PATCH 140/144] =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=A1=88=E4=BE=8B?= =?UTF-8?q?=E5=88=86=E7=A6=BB=E5=8D=95=E7=8B=AC=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 38 ++++-------- sa-token-doc/doc/more/link.md | 108 +++++++++++++++------------------- 2 files changed, 60 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 1cdd7413..7503808a 100644 --- a/README.md +++ b/README.md @@ -89,52 +89,40 @@ Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) ## Sa-Token 功能结构图 -![sa-token-js](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-js4.png 's-w') +![sa-token-js](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-js4.png) -![sa-token-rz](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-rz2.png 's-w') +![sa-token-rz](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-rz2.png) ## 使用Sa-Token的开源项目 -- [[ sa-plus ]](https://gitee.com/click33/sa-plus):一个基于 SpringBoot 架构的快速开发框架,内置代码生成器 -- [[ jthink ]](https://gitee.com/wtsoftware/jthink): 一个基于 SpringBoot + Sa-Token + Thymeleaf 的博客系统 - -- [[ dcy-fast ]](https://gitee.com/dcy421/dcy-fast): 一个基于 SpringBoot + Sa-Token + Mybatis-Plus 的后台管理系统,前端vue-element-admin,并且内置代码生成器 - -- [[ helio-starters ]](https://gitee.com/uncarbon97/helio-starters): 单体 Boot 版脚手架 + 微服务 Cloud 版脚手架,带有配套后台管理前端模板及代码生成器 - -- [[ sa-token-plugin ]](https://gitee.com/bootx/sa-token-plugin):Sa-Token第三方插件实现,基于Sa-Token-Core,提供一些与官方不同实现机制的的插件集合,作为Sa-Token开源生态的补充 - -- [[ easy-admin ]](https://gitee.com/lakernote/easy-admin):一个基于SpringBoot2 + Sa-Token + Mybatis-Plus + Snakerflow + Layui 的后台管理系统,灵活多变可前后端分离,也可单体,内置代码生成器、权限管理、工作流引擎等 +- [[ Sa-Plus ]](https://gitee.com/click33/sa-plus):一个基于 SpringBoot 架构的快速开发框架,内置代码生成器。 - [[ RuoYi-Vue-Plus ]](https://gitee.com/JavaLionLi/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 全方位升级 定期同步 -- [[ falser-cloud ]](https://gitee.com/falser/falser-cloud): 基于 SpringCloud Alibaba + SpringCloud gateway + SpringBoot + Sa-Token + vue-admin-template + Nacos + Rabbit MQ + Redis 的一个后台管理系统,前后端分离,权限管理,菜单管理,数据字典,停车场系统管理等功能 +- [[ EasyAdmin ]](https://gitee.com/lakernote/easy-admin):一个基于SpringBoot2 + Sa-Token + Mybatis-Plus + Snakerflow + Layui 的后台管理系统,灵活多变可前后端分离,也可单体,内置代码生成器、权限管理、工作流引擎等 -- [[ bootx-platform ]](https://gitee.com/bootx/bootx-platform):集成sa-token和sa-token-plugin并深度定制认证模块,包含多级别数据范围权限、数据自动加解密、数据脱敏、超级查询器、以及支付收单、消息通知等准商用功能的开源免费开发脚手架项目 +- [[ YC-Framework ]](http://framework.youcongtech.com/):致力于打造一款优秀的分布式微服务解决方案。 -- [[ QForum-Core ]](https://github.com/Project-QForum/QForum-Core/):QForum 论坛系统官方核心,可拓展性强、轻量级、高性能、前后端分离,基于 SpringBoot2 + Sa-Token + Mybatis-Plus +- [[ Pig-Satoken ]](https://gitee.com/wchenyang/cloud-satoken):重写 Pig 授权方式为 Sa-Token,其他代码不变。 -- [[ ExciteCMS-Layui ]](https://gitee.com/ExciteTeam/ExciteCMS-SpringBoot-Layui):ExciteCMS 快速开发脚手架:一款后端基于 SpringBoot2 + Sa-Token + Mybatis-Plus,前端基于 Layuimini 的内容管理系统,具备RBAC、日志管理、代码生成等功能,并集成常用的支付、OSS等第三方服务,拥有详细的开发文档 +更对开源案例可参考:[Awesome-Sa-Token](https://gitee.com/sa-token/awesome-sa-token) -- [[ 拾壹博客 ]](https://gitee.com/quequnlong/shiyi-blog):一款vue+springboot前后端分离的博客系统,博客后台管理系统使用了vue+elmentui开发,后端使用Sa-Token进行权限管理,支持动态菜单权限,动态定时任务,文件支持本地和七牛云上传,使用ElasticSearch作为全文检索服务,支持QQ、微博、码云登录。 - -如果您的项目使用了Sa-Token,欢迎提交pr ## 友情链接 -- [[ OkHttps ]](https://gitee.com/ejlchina-zhxu/okhttps):一个轻量级http通信框架,API设计无比优雅,支持 WebSocket 以及 Stomp 协议 +- [[ OkHttps ]](https://gitee.com/ejlchina-zhxu/okhttps):一个轻量级 http 通信框架,API无比优雅,支持 WebSocket、Stomp 协议 -- [[ Bean Searcher ]](https://github.com/ejlchina/bean-searcher):比 MyBatis 效率快 100 倍的条件检索引擎,天生支持联表,使一行代码实现复杂列表检索成为可能! +- [[ Bean Searcher ]](https://github.com/ejlchina/bean-searcher):比 MyBatis 效率快 100 倍的条件检索引擎,一行代码实现复杂列表检索! -- [[ 小诺快速开发平台 ]](https://xiaonuo.vip/index#pricing):基于SpringBoot2 + AntDesignVue全新快速开发平台,同时拥有三个版本 +- [[ 小诺快速开发平台 ]](https://xiaonuo.vip/index#pricing):基于SpringBoot2 + AntDesignVue全新快速开发平台,同时拥有三个版本。 -- [[ Jpom ]](https://gitee.com/dromara/Jpom):简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件 +- [[ Jpom ]](https://gitee.com/dromara/Jpom):简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件。 -- [[ TLog ]](https://gitee.com/dromara/TLog):一个轻量级的分布式日志标记追踪神器 +- [[ TLog ]](https://gitee.com/dromara/TLog):一个轻量级的分布式日志标记追踪神器。 -- [[ hippo4j ]](https://gitee.com/agentart/hippo4j):强大的动态线程池框架,附带监控报警功能 +- [[ hippo4j ]](https://gitee.com/agentart/hippo4j):强大的动态线程池框架,附带监控报警功能。 ## 知识星球 diff --git a/sa-token-doc/doc/more/link.md b/sa-token-doc/doc/more/link.md index d1c688a4..f2310b3d 100644 --- a/sa-token-doc/doc/more/link.md +++ b/sa-token-doc/doc/more/link.md @@ -1,53 +1,32 @@ # 框架生态 -> 如果您的开源项目使用了 Sa-Token,欢迎提交: -> -> - 项目必须是开源项目,且功能具有一定完备性,而不是一个临时 Demo。 -> - 可以是后台管理、插件、博客等任意类型的项目,无 star 数量要求,即使是刚刚开源的项目,也可以提交。 -> - 项目需要积极维护,积极处理 issue、pr,长时间没有更新代码将可能从本页面取消展示。 -> - 符合要求的项目直接通过项目 [issue](https://gitee.com/dromara/sa-token/issues) 或 [pr](https://gitee.com/dromara/sa-token/blob/dev/sa-token-doc/doc/more/link.md) 提交即可。 -> -> 经过 Sa-Token 开发组审核通过后: -> - 将展示在此页面。 -> - 在 Sa-Token 交流群中宣传推广,为项目带来流量。 -> - 按照 star 量排序择取前六名展示在官网首页。 ---- +> 集成 Sa-Token 的开源案例收集,取自 [Awesome-Sa-Token](https://gitee.com/sa-token/awesome-sa-token),定期同步。 + +--- -### 使用 Sa-Token 的开源项目: -1. [[ Sa-Plus ]](https://gitee.com/click33/sa-plus):一个基于 SpringBoot 架构的快速开发框架,内置代码生成器 -- [[ jthink ]](https://gitee.com/wtsoftware/jthink): 一个基于 SpringBoot + Sa-Token + Thymeleaf 的博客系统 +### 后台管理 -- [[ dcy-fast ]](https://gitee.com/dcy421/dcy-fast):一个基于 SpringBoot + Sa-Token + Mybatis-Plus 的后台管理系统,前端vue-element-admin,并且内置代码生成器 +- [[ Sa-Plus ]](https://gitee.com/click33/sa-plus):一个基于 SpringBoot 架构的快速开发框架,内置代码生成器。 + +- [[ dcy-fast ]](https://gitee.com/dcy421/dcy-fast):一个基于 SpringBoot + Sa-Token + Mybatis-Plus 的后台管理系统,前端vue-element-admin,并且内置代码生成器。 - [[ Helio-Starters ]](https://gitee.com/uncarbon97/helio-starters):基于JDK15 + Spring Boot 2.4 + Sa-Token + Mybatis-Plus的单体Boot版脚手架和微服务Cloud版脚手架,带有配套后台管理前端模板及代码生成器 -- [[ Sa-Token-Plugin ]](https://gitee.com/bootx/sa-token-plugin):Sa-Token第三方插件实现,基于Sa-Token-Core,提供一些与官方不同实现机制的的插件集合,作为Sa-Token开源生态的补充 - - [[ EasyAdmin ]](https://gitee.com/lakernote/easy-admin):一个基于SpringBoot2 + Sa-Token + Mybatis-Plus + Snakerflow + Layui 的后台管理系统,灵活多变可前后端分离,也可单体,内置代码生成器、权限管理、工作流引擎等 - [[ RuoYi-Vue-Plus ]](https://gitee.com/JavaLionLi/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 + Sa-Token + Dubbo + Mybatis-Plus + Xxl-Job 全方位升级 定期同步 - - [[ SpringBoot_v2 ]](https://gitee.com/bdj/SpringBoot_v2):SpringBoot_v2项目是努力打造springboot框架的极致细腻的脚手架。 -- [[ Sa-Token-Study ]](https://gitee.com/click33/sa-token-study):以demo示例的方式讲解 Sa-Token 源码涉及到的技术点,连载中…… - -- [[ Sp-Cloud ]](https://gitee.com/click33/sp-cloud):Sa-Plus的微服务版本, 基于Spring-Cloud-Alibaba,微服务下使用Sa-Token的样例 - - [[ Ruoyi-Satoken ]](https://gitee.com/wangming123456/ruoyi-satoken):为 ruoyi 进行配置 sa-token - [[ vue-satoken-admin ]](https://gitee.com/niluni/vue-satoken-admin):基于Vue2和Sa-Token1.18.0的后台权限系统。 - [[ 人事管理系统后端 ]](https://gitee.com/sdones_1512/personnel-management-system-back-end):人事管理系统后端,框架:springboot,持久层:mybatis,缓存:redis,权限:sa-token -- [[ YC-Framework ]](http://framework.youcongtech.com/):致力于打造一款优秀的分布式微服务解决方案 - -- [[ falser-cloud ]](https://gitee.com/falser/falser-cloud): 基于 SpringCloud Alibaba + SpringCloud gateway + SpringBoot + Sa-Token + vue-admin-template + Nacos + Rabbit MQ + Redis 的一个后台管理系统,前后端分离,权限管理,菜单管理,数据字典,停车场系统管理等功能 - - [[ bootx-platform ]](https://gitee.com/bootx/bootx-platform):集成sa-token和sa-token-plugin并深度定制认证模块,包含多级别数据范围权限、数据自动加解密、数据脱敏、超级查询器、以及支付收单、消息通知等准商用功能的开源免费开发脚手架项目 - [[ spba-admin ]](https://gitee.com/qkdja/spring-boot-admin):基于SpringBoot、Vue开发的通用后台管理系统,做到开箱即用,为新项目开发省去了基础功能开发的步骤。主要使用Sa-Token权限认证、MyBatis-Plus、MySQL、Redis、validation、七牛云等技术。 @@ -58,51 +37,58 @@ - [[ sss-rbac-admin ]](https://gitee.com/momoljw/sss-rbac-admin):基于springboot,整合satoken、sqltoy的权限管理系统 -- [[ Huanxing-mall ]](https://gitee.com/lijiaxing_boy/huanxing-mall):HuanXing 商城基于SpringCloud 2021 & Alibaba + Sa-token,前端基于 Vue3 +Element plus 的微服务商城 - -- [[ SpringMvc+Sa-Token ]](https://gitee.com/SRD_01/spring-mvc-sa-token): Jsp+SpringMVC+SSO+Sa-Token+Redis | Spring MVC 集成 SaToken Demo 项目 - - [[ QuickBuild ]](https://gitee.com/CodeLiQing/custom-quick-build-platform): 快速构建 | 基于springboot+sa-token+neety+代码生产器(生成vue页面和增删改查代码)| 以及前端vue3和字节arco.design框架整合 -- [[ iot-kit ]](https://gitee.com/iotkit-open-source/iotkit-parent):一个轻量级低门槛的物联网平台,包含了多协议设备接入、规则引擎、第三方平台接入、智能家居小程序等模块的项目,基于SpringBoot架构并集成了Sa-Token的OAuth2认证。 - -- [[ 拾壹博客 ]](https://gitee.com/quequnlong/shiyi-blog.git):一款vue+springboot前后端分离的博客系统,博客后台管理系统使用了vue+elmentui开发,后端使用Sa-Token进行权限管理,支持动态菜单权限,动态定时任务,文件支持本地和七牛云上传,使用ElasticSearch作为全文检索服务,支持QQ、微博、码云登录。 - -- [[ dcy-fast-cloud ]](https://gitee.com/dcy421/dcy-fast-cloud):一个基于 SpringCloudAlibaba + Sa-Token + dubbo2.7.8 + Seata + knife4j + Mybatis-Plus + MapStruct + 的后台管理系统,前端vue-element-admin,并且内置代码生成器+动态路由权限等功能 - - [[ magic-boot ]](https://gitee.com/ssssssss-team/magic-boot):基于 magic-api + Sa-Token 搭建的快速开发平台,可以实现在浏览器编写Vue代码,既改即生效 -- [[ fhs-framework ]](https://gitee.com/fhs-opensource/fhs-framework):基于Springboot+Springcloud + Mybatis Plus + sa-token+ vue + elementui 的快速开发平台(低代码开发平台),本框架永远免费,永久全开源 - - [[ chaos ]](https://gitee.com/qishanor/chaos):一个基于 SpringBoot + Sa-Token + Mybatis-Plus的快速开发框架,前端vue-element-avue,内置代码生成器,代码最简洁,最佳学习实践方案。 + + +### 微服务相关 + +- [[ RuoYi-Cloud-Plus ]](https://gitee.com/JavaLionLi/RuoYi-Cloud-Plus):重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba + Sa-Token + Dubbo + Mybatis-Plus + Xxl-Job 全方位升级 定期同步 + +- [[ Sp-Cloud ]](https://gitee.com/click33/sp-cloud):Sa-Plus的微服务版本, 基于Spring-Cloud-Alibaba,微服务下使用Sa-Token的样例 + +- [[ YC-Framework ]](http://framework.youcongtech.com/):致力于打造一款优秀的分布式微服务解决方案 + +- [[ 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 的快速开发平台(低代码开发平台),本框架永远免费,永久全开源 + - [[ Pig-Satoken ]](https://gitee.com/wchenyang/cloud-satoken):重写 Pig 授权方式为 Sa-Token,其他代码不变。 +### 插件 + +- [[ Sa-Token-Plugin ]](https://gitee.com/bootx/sa-token-plugin):Sa-Token第三方插件实现,基于Sa-Token-Core,提供一些与官方不同实现机制的的插件集合,作为Sa-Token开源生态的补充 + +- [[ quarkus-sa-token ]](https://github.com/quarkiverse/quarkus-sa-token): quarkus 整合 Sa-Token。 + + + +### 其它 + +- [[ jthink ]](https://gitee.com/wtsoftware/jthink): 一个基于 SpringBoot + Sa-Token + Thymeleaf 的博客系统 + +- [[ Sa-Token-Study ]](https://gitee.com/click33/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命令集、依赖分析等等等,助你快速定位问题。 -
    --- -### 推荐项目: - -- [[ OkHttps ]](https://gitee.com/ejlchina-zhxu/okhttps):一个轻量级 http 通信框架,API设计无比优雅,支持 WebSocket 以及 Stomp 协议 - -- [[ Hasor ]](https://gitee.com/zycgit/hasor) :轻量级ioc/aop框架,采用"微内核+插件"的设计思想 - -- [[ Sa-Admin ]](https://gitee.com/click33/sa-admin) :一个多窗口后台模板,流畅、易上手、提高生产力 - -- [[ vue-next-admin ]](https://gitee.com/lyt-top/vue-next-admin) :一套为开发者快速开发准备的基于 vue2.x 越看越精彩的后台管理系统一站式平台模板 - -- [[ 小诺快速开发平台 ]](https://xiaonuo.vip/index#pricing):基于SpringBoot2 + AntDesignVue全新快速开发平台,同时拥有三个版本 - -- [[ Jpom ]](https://gitee.com/dromara/Jpom):简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件 - -- [[ TLog ]](https://gitee.com/dromara/TLog):一个轻量级的分布式日志标记追踪神器 - - -
    -虚位以待... - +Sa-Token 在线文档:[https://sa-token.dev33.cn/](https://sa-token.dev33.cn/) From e0e3dc49d11aeea9a9cff9320017954cad9b8c37 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 24 Aug 2022 13:15:42 +0800 Subject: [PATCH 141/144] =?UTF-8?q?=E4=BC=98=E5=8C=96=20readme.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7503808a..58e3f563 100644 --- a/README.md +++ b/README.md @@ -112,11 +112,11 @@ Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) ## 友情链接 -- [[ OkHttps ]](https://gitee.com/ejlchina-zhxu/okhttps):一个轻量级 http 通信框架,API无比优雅,支持 WebSocket、Stomp 协议 +- [[ OkHttps ]](https://gitee.com/ejlchina-zhxu/okhttps):轻量级 http 通信框架,API无比优雅,支持 WebSocket、Stomp 协议 -- [[ Bean Searcher ]](https://github.com/ejlchina/bean-searcher):比 MyBatis 效率快 100 倍的条件检索引擎,一行代码实现复杂列表检索! +- [[ Bean Searcher ]](https://github.com/ejlchina/bean-searcher):专注高级查询的只读 ORM,使一行代码实现复杂列表检索! -- [[ 小诺快速开发平台 ]](https://xiaonuo.vip/index#pricing):基于SpringBoot2 + AntDesignVue全新快速开发平台,同时拥有三个版本。 +- [[ Snowy ]](https://xiaonuo.vip/index#pricing):小诺快速开发平台,同时拥有 Layui、Vue、SpringCloud 三个版本。 - [[ Jpom ]](https://gitee.com/dromara/Jpom):简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件。 From c74dfac8f2ef1f14d9c4a3dcf6e39b153b5dde1d Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 24 Aug 2022 18:07:24 +0800 Subject: [PATCH 142/144] =?UTF-8?q?=E4=BC=98=E5=8C=96readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58e3f563..0e79fb17 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Sa-Token-SSO 由简入难划分为三种模式,解决不同架构下的 SSO 3. 如果既无法做到前端同域,也无法做到后端同Redis,那么只能走模式三,Http请求获取会话(Sa-Token对SSO提供了完整的封装,你只需要按照示例从文档上复制几段代码便可以轻松集成) ## Sa-Token-OAuth2.0 授权登录 -Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) 编写,通过Sa-OAuth2你可以非常轻松的实现系统的OAuth2.0授权认证 +Sa-OAuth2 模块分为四种授权模式,解决不同场景下的授权需求 | 授权模式 | 简介 | | :-------- | :-------- | From c7968826b60e4be42d3fc1738314f84810975c59 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 24 Aug 2022 18:07:51 +0800 Subject: [PATCH 143/144] =?UTF-8?q?=E9=87=8D=E6=9E=84=20spliceTwoUrl=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=88=B0=20SaFoxUtil=20=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/dev33/satoken/strategy/SaStrategy.java | 43 ++++--------------- .../java/cn/dev33/satoken/util/SaFoxUtil.java | 26 +++++++++++ .../cn/dev33/satoken/config/SaSsoConfig.java | 9 ++-- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java index eaef034b..f3f127a0 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java @@ -172,7 +172,7 @@ public final class SaStrategy { }; /** - * 从元素上获取注解(注解鉴权内部实现) + * 从元素上获取注解 *

    参数 [element元素,要获取的注解类型] */ public BiFunction , Annotation> getAnnotation = (element, annotationClass)->{ @@ -182,7 +182,6 @@ public final class SaStrategy { /** * 判断一个 Method 或其所属 Class 是否包含指定注解 - * *

    参数 [Method, 注解] */ public BiFunction isAnnotationPresent = (method, annotationClass) -> { @@ -190,29 +189,6 @@ public final class SaStrategy { me.getAnnotation.apply(method.getDeclaringClass(), SaIgnore.class) != null; }; - /** - * 拼接两个url - *

    例如:url1=http://domain.cn,url2=/sso/auth,则返回:http://domain.cn/sso/auth - *

    参数 [第一个url, 第二个url] - */ - public BiFunction spliceTwoUrl = (url1, url2) -> { - // q1、任意一个为空,则直接返回另一个 - if(url1 == null) { - return url2; - } - if(url2 == null) { - return url1; - } - - // q2、如果 url2 以 http 开头,将其视为一个完整地址 - if(url2.startsWith("http")) { - return url2; - } - - // q3、将两个地址拼接在一起 - return url1 + url2; - }; - // // 重写策略 set连缀风格 @@ -275,7 +251,7 @@ public final class SaStrategy { } /** - * 从元素上获取注解(注解鉴权内部实现) + * 从元素上获取注解 *

    参数 [element元素,要获取的注解类型] * @param getAnnotation / * @return 对象自身 @@ -286,15 +262,14 @@ public final class SaStrategy { } /** - * 拼接两个url - *

    例如:url1=http://domain.cn,url2=/sso/auth,则返回:http://domain.cn/sso/auth - *

    参数 [第一个url, 第二个url] - * - * @param spliceTwoUrl 要设置的 spliceTwoUrl + * 判断一个 Method 或其所属 Class 是否包含指定注解 + *

    参数 [Method, 注解] + * @param isAnnotationPresent / + * @return 对象自身 */ - public void setSpliceTwoUrl(BiFunction spliceTwoUrl) { - this.spliceTwoUrl = spliceTwoUrl; + public SaStrategy setIsAnnotationPresent(BiFunction isAnnotationPresent) { + this.isAnnotationPresent = isAnnotationPresent; + return this; } - } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java index d0fcdb74..50af1be7 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java @@ -333,6 +333,32 @@ public class SaFoxUtil { } return joinSharpParam(url, key + "=" + value); } + + /** + * 拼接两个url + *

    例如:url1=http://domain.cn,url2=/sso/auth,则返回:http://domain.cn/sso/auth

    + * + * @param url1 第一个url + * @param url2 第二个url + * @return 拼接完成的url + */ + public static String spliceTwoUrl(String url1, String url2) { + // q1、任意一个为空,则直接返回另一个 + if(url1 == null) { + return url2; + } + if(url2 == null) { + return url1; + } + + // q2、如果 url2 以 http 开头,将其视为一个完整地址 + if(url2.startsWith("http")) { + return url2; + } + + // q3、将两个地址拼接在一起 + return url1 + url2; + } /** * 将数组的所有元素使用逗号拼接在一起 diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java index 0d8253d8..5ec0a52d 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java @@ -7,7 +7,6 @@ import java.util.function.Function; import java.util.function.Supplier; import cn.dev33.satoken.exception.SaTokenException; -import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaResult; @@ -323,28 +322,28 @@ public class SaSsoConfig implements Serializable { * @return 获取拼接url:Server 端单点登录授权地址 */ public String splicingAuthUrl() { - return SaStrategy.me.spliceTwoUrl.apply(getServerUrl(), getAuthUrl()); + return SaFoxUtil.spliceTwoUrl(getServerUrl(), getAuthUrl()); } /** * @return 获取拼接url:Server 端的 ticket 校验地址 */ public String splicingCheckTicketUrl() { - return SaStrategy.me.spliceTwoUrl.apply(getServerUrl(), getCheckTicketUrl()); + return SaFoxUtil.spliceTwoUrl(getServerUrl(), getCheckTicketUrl()); } /** * @return 获取拼接url:Server 端查询 userinfo 地址 */ public String splicingUserinfoUrl() { - return SaStrategy.me.spliceTwoUrl.apply(getServerUrl(), getUserinfoUrl()); + return SaFoxUtil.spliceTwoUrl(getServerUrl(), getUserinfoUrl()); } /** * @return 获取拼接url:Server 端单点注销地址 */ public String splicingSloUrl() { - return SaStrategy.me.spliceTwoUrl.apply(getServerUrl(), getSloUrl()); + return SaFoxUtil.spliceTwoUrl(getServerUrl(), getSloUrl()); } /** From 00f8d120f8e24e40685ac67efe995b2b7b67e459 Mon Sep 17 00:00:00 2001 From: KuroNeko <38455940+xiaomujin@users.noreply.github.com> Date: Thu, 25 Aug 2022 14:02:38 +0800 Subject: [PATCH 144/144] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E6=97=B6=E9=97=B4=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2021-08-18 -> 2022-08-18 --- sa-token-doc/doc/fun/timeline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sa-token-doc/doc/fun/timeline.md b/sa-token-doc/doc/fun/timeline.md index f5e60236..c82002ef 100644 --- a/sa-token-doc/doc/fun/timeline.md +++ b/sa-token-doc/doc/fun/timeline.md @@ -26,6 +26,6 @@ - **2021-12-27:** 荣获 OSC-2021 最佳软件 Top 30。 - **2022-05-20:** 成为 [可信开源社区共同体] 预备成员。 - **2022-08-01:** 加入 [中国开源社区 landscape]。 -- **2021-08-18:** GitHub 第 10000 个 star 里程碑! +- **2022-08-18:** GitHub 第 10000 个 star 里程碑!