diff --git a/sa-token-demo/sa-token-demo-remember-me/page_project/.gitignore b/sa-token-demo/sa-token-demo-remember-me/page_project/.gitignore new file mode 100644 index 00000000..cc5b432e --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/page_project/.gitignore @@ -0,0 +1,23 @@ +# vite创建项目时自动生成的git忽略配置文件 +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/sa-token-demo/sa-token-demo-remember-me/page_project/README.md b/sa-token-demo/sa-token-demo-remember-me/page_project/README.md new file mode 100644 index 00000000..6be21563 --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/page_project/README.md @@ -0,0 +1,11 @@ +# Vue 3 + Vite + +[Node下载地址](https://nodejs.org/zh-cn/) + +安装最新版本Node环境, 然后执行如下命令开启开发服务: +``` +npm install +npm run dev +``` + +[cookie/sessionstorage/localstorage三者的区别](https://blog.csdn.net/weixin_45541388/article/details/125367823) diff --git a/sa-token-demo/sa-token-demo-remember-me/page_project/index.html b/sa-token-demo/sa-token-demo-remember-me/page_project/index.html new file mode 100644 index 00000000..6bb3cf29 --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/page_project/index.html @@ -0,0 +1,12 @@ + + + + + + 记住我模式Demo页面 + + +
+ + + diff --git a/sa-token-demo/sa-token-demo-remember-me/page_project/package.json b/sa-token-demo/sa-token-demo-remember-me/page_project/package.json new file mode 100644 index 00000000..aab21333 --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/page_project/package.json @@ -0,0 +1,22 @@ +{ + "name": "page_project", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "axios": "^1.3.4", + "element-plus": "^2.2.33", + "qs": "^6.11.0", + "vue": "^3.2.45", + "vue-axios": "^3.5.2" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^4.0.0", + "vite": "^4.1.0" + } +} diff --git a/sa-token-demo/sa-token-demo-remember-me/page_project/src/App.vue b/sa-token-demo/sa-token-demo-remember-me/page_project/src/App.vue new file mode 100644 index 00000000..a39e2dd0 --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/page_project/src/App.vue @@ -0,0 +1,160 @@ + + + + + \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-remember-me/page_project/src/main.js b/sa-token-demo/sa-token-demo-remember-me/page_project/src/main.js new file mode 100644 index 00000000..6f63545f --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/page_project/src/main.js @@ -0,0 +1,20 @@ +import { createApp } from 'vue' +import App from './App.vue' +import axios from 'axios' // 请求发送接收工具 +import VueAxios from 'vue-axios' // vue封装axios +import qs from 'qs' // axios请求参数类型封装 +import ElementPlus from 'element-plus' // elementUI for vue3 +import 'element-plus/dist/index.css' // 加载elementUI样式 +import zhCn from 'element-plus/es/locale/lang/zh-cn' // 引入中文本地化组件 + + +const app = createApp(App) + +// vue组件内通过 this.$f() 来调用 +app.config.globalProperties.$f = (params) => { + return qs.stringify(params) +} + +app.use(VueAxios, axios) +.use(ElementPlus, { locale: zhCn }) +.mount('#app') diff --git a/sa-token-demo/sa-token-demo-remember-me/page_project/vite.config.js b/sa-token-demo/sa-token-demo-remember-me/page_project/vite.config.js new file mode 100644 index 00000000..f4ad736d --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/page_project/vite.config.js @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// 开启代理服务 +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue()], + server: { + port: 5173, + host: true, + proxy: { + '^/back/.*$': { + target: 'http://localhost:80' + } + } + } +}) diff --git a/sa-token-demo/sa-token-demo-remember-me/server_project/pom.xml b/sa-token-demo/sa-token-demo-remember-me/server_project/pom.xml new file mode 100644 index 00000000..af9c50ef --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/server_project/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + cn.dev33 + remember_me + 1.0-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-parent + 2.5.14 + + + + + 1.34.0 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + cn.dev33 + sa-token-spring-boot-starter + ${sa-token.version} + + + + + cn.dev33 + sa-token-dao-redis-jackson + ${sa-token.version} + + + org.apache.commons + commons-pool2 + + + \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-remember-me/server_project/src/main/java/cc/sa_token/RememberMeApplication.java b/sa-token-demo/sa-token-demo-remember-me/server_project/src/main/java/cc/sa_token/RememberMeApplication.java new file mode 100644 index 00000000..ab7757bc --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/server_project/src/main/java/cc/sa_token/RememberMeApplication.java @@ -0,0 +1,11 @@ +package cc.sa_token; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RememberMeApplication { + public static void main(String[] args) { + SpringApplication.run(RememberMeApplication.class, args); + } +} \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-remember-me/server_project/src/main/java/cc/sa_token/controller/UserLoginController.java b/sa-token-demo/sa-token-demo-remember-me/server_project/src/main/java/cc/sa_token/controller/UserLoginController.java new file mode 100644 index 00000000..fcfd7fe1 --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/server_project/src/main/java/cc/sa_token/controller/UserLoginController.java @@ -0,0 +1,37 @@ +package cc.sa_token.controller; + +import cn.dev33.satoken.stp.SaTokenInfo; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.util.SaResult; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/back/user") +public class UserLoginController { + + @RequestMapping("/login") + public SaResult doLogin(String name, String pwd, Boolean remember) { + if("zhang".equals(name) && "123456".equals(pwd)) { + StpUtil.login(10001, remember); + SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); + return SaResult.ok() + .set("tokenName", tokenInfo.getTokenName()) + .set("tokenValue", tokenInfo.getTokenValue()); + } else { + return SaResult.error("登录失败"); + } + } + + @RequestMapping("/state") + public SaResult checkNowLoginState() { + return SaResult.ok().setData(StpUtil.isLogin()); + } + + @RequestMapping("/logout") + public SaResult doLogout() { + StpUtil.logout(); + return SaResult.ok().setData(StpUtil.isLogin()); + } + +} diff --git a/sa-token-demo/sa-token-demo-remember-me/server_project/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-remember-me/server_project/src/main/resources/application.yml new file mode 100644 index 00000000..424afda2 --- /dev/null +++ b/sa-token-demo/sa-token-demo-remember-me/server_project/src/main/resources/application.yml @@ -0,0 +1,51 @@ +# 端口 +server: + port: 80 + +# sa-token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: satoken + # token有效期,单位s 默认30天, -1代表永不过期 + timeout: 2592000 + # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 + activity-timeout: -1 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 禁止写入cookie + is-read-cookie: false + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # token风格 + token-style: uuid + # 是否输出操作日志 + is-log: false + +spring: + # redis配置 + redis: + # Redis数据库索引(默认为0) + database: 0 + # Redis服务器地址 + host: 127.0.0.1 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: + # 连接超时时间 + timeout: 10s + lettuce: + pool: + # 连接池最大连接数 + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + # 连接池中的最大空闲连接 + max-idle: 10 + # 连接池中的最小空闲连接 + min-idle: 0 + + + + + \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-solon/pom.xml b/sa-token-demo/sa-token-demo-solon/pom.xml index 5a91e468..ffaed51b 100644 --- a/sa-token-demo/sa-token-demo-solon/pom.xml +++ b/sa-token-demo/sa-token-demo-solon/pom.xml @@ -10,7 +10,7 @@ 1.34.0 - 1.12.4 + 2.2.1 UTF-8 UTF-8 diff --git a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/SaTokenDemoApp.java b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/SaTokenDemoApp.java index 6607050d..8173ea54 100644 --- a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/SaTokenDemoApp.java +++ b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/SaTokenDemoApp.java @@ -2,6 +2,7 @@ package com.pj; import org.noear.solon.Solon; +import org.noear.solon.annotation.SolonMain; import cn.dev33.satoken.SaManager; @@ -10,6 +11,7 @@ import cn.dev33.satoken.SaManager; * @author noear * */ +@SolonMain public class SaTokenDemoApp { public static void main(String[] args) { diff --git a/sa-token-demo/sa-token-demo-solon/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-solon/src/main/resources/app.yml similarity index 100% rename from sa-token-demo/sa-token-demo-solon/src/main/resources/application.yml rename to sa-token-demo/sa-token-demo-solon/src/main/resources/app.yml diff --git a/sa-token-demo/sa-token-demo-sso-server-solon/pom.xml b/sa-token-demo/sa-token-demo-sso-server-solon/pom.xml index fda1c56e..b4428659 100644 --- a/sa-token-demo/sa-token-demo-sso-server-solon/pom.xml +++ b/sa-token-demo/sa-token-demo-sso-server-solon/pom.xml @@ -9,7 +9,7 @@ 1.34.0 - 1.12.4 + 2.2.1 diff --git a/sa-token-demo/sa-token-demo-sso-server-solon/src/main/java/com/pj/SaSsoServerApp.java b/sa-token-demo/sa-token-demo-sso-server-solon/src/main/java/com/pj/SaSsoServerApp.java index 29ba2013..82fae5d6 100644 --- a/sa-token-demo/sa-token-demo-sso-server-solon/src/main/java/com/pj/SaSsoServerApp.java +++ b/sa-token-demo/sa-token-demo-sso-server-solon/src/main/java/com/pj/SaSsoServerApp.java @@ -2,7 +2,9 @@ package com.pj; import org.noear.solon.Solon; +import org.noear.solon.annotation.SolonMain; +@SolonMain public class SaSsoServerApp { public static void main(String[] args) { diff --git a/sa-token-dependencies/pom.xml b/sa-token-dependencies/pom.xml index 63c7f8f2..8d17df16 100644 --- a/sa-token-dependencies/pom.xml +++ b/sa-token-dependencies/pom.xml @@ -23,9 +23,9 @@ 3.1.0 6.0.0 3.0.9.RELEASE - 1.12.4 + 2.2.1 1.4.5 - 3.2.50 + 3.2.54 4.9.17 3.14.4 2.5.0 diff --git a/sa-token-doc/fun/session-model.md b/sa-token-doc/fun/session-model.md index ef26e323..4d2fd66c 100644 --- a/sa-token-doc/fun/session-model.md +++ b/sa-token-doc/fun/session-model.md @@ -80,6 +80,12 @@ session.set("name", "张三"); 只要两个自定义Session的Id一致,它们就是同一个Session +Custom-Session的会话有效期默认使用`SaManager.getConfig().getTimeout()`, 如果需要修改会话有效期, 可以在创建之后, 使用对象方法修改 + +``` java +session.updateTimeout(1000); // 参数说明和全局有效期保持一致 +``` + ### 4、Session模型结构图 diff --git a/sa-token-doc/fun/token-timeout.md b/sa-token-doc/fun/token-timeout.md index 9faa9cb2..df5b7f27 100644 --- a/sa-token-doc/fun/token-timeout.md +++ b/sa-token-doc/fun/token-timeout.md @@ -95,7 +95,6 @@ StpUtil.stpLogic.updateLastActivityToNow(tokenValue); | StpUtil.getLoginIdAsLong() | |---| | StpUtil.getSession() | -| StpUtil.getSession() | | StpUtil.getTokenSession() | |---| | StpUtil.getRoleList() | diff --git a/sa-token-doc/more/blog.md b/sa-token-doc/more/blog.md index dea27d98..499b09b4 100644 --- a/sa-token-doc/more/blog.md +++ b/sa-token-doc/more/blog.md @@ -1,6 +1,6 @@ # 框架博客 -> 此页面收集 Sa-Token 相关技术文章,欢迎大家投稿(不限平台,按照发表日期倒叙), +> 此页面收集 Sa-Token 相关技术文章,欢迎大家投稿(不限平台,按照发表日期倒序), > [投稿链接](https://wj.qq.com/s2/10596458/aa96/) --- diff --git a/sa-token-doc/more/common-action.md b/sa-token-doc/more/common-action.md index 504a160d..db92396f 100644 --- a/sa-token-doc/more/common-action.md +++ b/sa-token-doc/more/common-action.md @@ -45,7 +45,6 @@ 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(dataList, prefix, keyword, start, size, sortType); // 从集合里查询数据 diff --git a/sa-token-doc/plugin/jwt-extend.md b/sa-token-doc/plugin/jwt-extend.md index 2b2d5cdb..4897b337 100644 --- a/sa-token-doc/plugin/jwt-extend.md +++ b/sa-token-doc/plugin/jwt-extend.md @@ -27,6 +27,8 @@ implementation 'cn.dev33:sa-token-jwt:${sa.top.version}' > 注意: sa-token-jwt 显式依赖 hutool-jwt 5.7.14 版本,意味着:你的项目中要么不引入 Hutool,要么引入版本 >= 5.7.14 的 Hutool 版本 +> hutool 5.8.13 和 5.8.14 禁止使用, [关联issue](https://gitee.com/dromara/sa-token/issues/I6L429) + ### 2、配置秘钥 在 `application.yml` 配置文件中配置 jwt 生成秘钥: @@ -139,8 +141,8 @@ eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbklkIjoiMTAwMDEiLCJybiI6IjZYYzgySzB | 功能点 | Simple 简单模式 | Mixin 混入模式 | Stateless 无状态模式 | | :-------- | :-------- | :-------- | :-------- | | Token风格 | jwt风格 | jwt风格 | jwt风格 | -| 登录数据存储 | Redis中 | Token中 | Token中 | -| Session存储 | Redis中 | Redis中 | 无Session | +| 登录数据存储 | Redis中存储 | Token中存储 | Token中存储 | +| Session存储 | Redis中存储 | Redis中存储 | 无Session | | 注销下线 | 前后端双清数据 | 前后端双清数据 | 前端清除数据 | | 踢人下线API | 支持 | 不支持 | 不支持 | | 顶人下线API | 支持 | 不支持 | 不支持 | diff --git a/sa-token-doc/plugin/quick-login.md b/sa-token-doc/plugin/quick-login.md index a2a937ce..94961c73 100644 --- a/sa-token-doc/plugin/quick-login.md +++ b/sa-token-doc/plugin/quick-login.md @@ -48,7 +48,13 @@ Sa-Token-Quick-Login的定位是这样的场景:你的项目需要一个登录 ``` xml - + + + cn.dev33 + sa-token-spring-boot-starter + ${sa.top.version} + + cn.dev33 sa-token-quick-login @@ -57,6 +63,8 @@ Sa-Token-Quick-Login的定位是这样的场景:你的项目需要一个登录 ``` ``` gradle +// Sa-Token 启动依赖 +implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}' // Sa-Token-Quick-Login 插件 implementation 'cn.dev33:sa-token-quick-login:${sa.top.version}' ``` diff --git a/sa-token-doc/start/example.md b/sa-token-doc/start/example.md index 00fc3c97..8d6fd50b 100644 --- a/sa-token-doc/start/example.md +++ b/sa-token-doc/start/example.md @@ -13,6 +13,8 @@ ### 2、添加依赖 在项目中添加依赖: +> 注:如果你使用的 `SpringBoot 3.x`,只需要将 `sa-token-spring-boot-starter` 修改为 `sa-token-spring-boot3-starter` 即可。 + ``` xml @@ -30,7 +32,6 @@ implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}' ``` -注:如果你使用的 `SpringBoot 3.x`,只需要将 `sa-token-spring-boot-starter` 修改为 `sa-token-spring-boot3-starter` 即可。 Maven依赖一直无法加载成功?[参考解决方案](https://sa-token.cc/doc.html#/start/maven-pull) 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 d6be13e3..5966c3b3 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 @@ -1,7 +1,6 @@ package cn.dev33.satoken.dao; import org.noear.redisx.RedisClient; -import org.noear.solon.annotation.Note; import java.util.Properties; @@ -11,7 +10,6 @@ import java.util.Properties; * @author noear * @since 1.6 */ -@Note("更名为:SaTokenDaoOfRedisBase64") @Deprecated public class SaTokenDaoOfRedis extends SaTokenDaoOfRedisBase64 { diff --git a/sa-token-starter/sa-token-solon-plugin/pom.xml b/sa-token-starter/sa-token-solon-plugin/pom.xml index 1827ce72..01471578 100644 --- a/sa-token-starter/sa-token-solon-plugin/pom.xml +++ b/sa-token-starter/sa-token-solon-plugin/pom.xml @@ -41,5 +41,17 @@ true + + org.noear + snack3 + provided + + + + org.noear + redisx + provided + + \ No newline at end of file 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 f67a32ee..b08c54d1 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,7 +3,6 @@ package cn.dev33.satoken.solon; import cn.dev33.satoken.solon.oauth2.SaOAuth2AutoConfigure; import cn.dev33.satoken.solon.sso.SaSsoAutoConfigure; import org.noear.solon.Solon; -import org.noear.solon.Utils; import org.noear.solon.core.AopContext; import org.noear.solon.core.Plugin; @@ -40,23 +39,11 @@ public class XPluginImp implements Plugin { //注入其它 Bean - context.beanOnloaded(c -> { - beanInitDo(c); - ssoBeanInitDo(c); - oauth2BeanInitDo(c); - }); - } - - private void ssoBeanInitDo(AopContext context){ - if (Utils.loadClass("cn.dev33.satoken.sso.SaSsoManager") != null) { + context.lifecycle(-99, () -> { + beanInitDo(context); context.beanMake(SaSsoAutoConfigure.class); - } - } - - private void oauth2BeanInitDo(AopContext context){ - if(Utils.loadClass("cn.dev33.satoken.oauth2.SaOAuth2Manager") != null){ context.beanMake(SaOAuth2AutoConfigure.class); - } + }); } private void beanInitDo(AopContext context) { diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaSessionForJson.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaSessionForJson.java new file mode 100644 index 00000000..9e7bc042 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaSessionForJson.java @@ -0,0 +1,73 @@ +package cn.dev33.satoken.solon.dao; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.util.SaFoxUtil; +import org.noear.snack.ONode; + +/** + * Snack3 定制版 SaSession,重写类型转换API + * + * @author noear + * @since 1.12 + */ +public class SaSessionForJson extends SaSession { + + private static final long serialVersionUID = -7600983549653130681L; + + public SaSessionForJson() { + super(); + } + + /** + * 构建一个 SaSession 对象 + * @param id Session 的 id + */ + public SaSessionForJson(String id) { + super(id); + } + + /** + * 取值 (指定转换类型) + * @param 泛型 + * @param key key + * @param cs 指定转换类型 + * @return 值 + */ + @Override + public T getModel(String key, Class cs) { + if(SaFoxUtil.isBasicType(cs)) { + return SaFoxUtil.getValueByType(get(key), cs); + } + return ONode.deserialize(getString(key), cs); + } + + /** + * 取值 (指定转换类型, 并指定值为Null时返回的默认值) + * @param 泛型 + * @param key key + * @param cs 指定转换类型 + * @param defaultValue 值为Null时返回的默认值 + * @return 值 + */ + @Override + @SuppressWarnings("unchecked") + public T getModel(String key, Class cs, Object defaultValue) { + Object value = get(key); + if(valueIsNull(value)) { + return (T)defaultValue; + } + if(SaFoxUtil.isBasicType(cs)) { + return SaFoxUtil.getValueByType(get(key), cs); + } + return ONode.deserialize(getString(key), cs); + } + + /** + * 忽略 timeout 字段的序列化 + */ + @Override + public long getTimeout() { + return super.getTimeout(); + } + +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedis.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedis.java new file mode 100644 index 00000000..805b5f4b --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedis.java @@ -0,0 +1,23 @@ +package cn.dev33.satoken.solon.dao; + +import org.noear.redisx.RedisClient; +import org.noear.solon.annotation.Note; + +import java.util.Properties; + +/** + * SaTokenDao 的 redis 适配 + * + * @author noear + * @since 1.6 + */ +public class SaTokenDaoOfRedis extends SaTokenDaoOfRedisBase64 { + + public SaTokenDaoOfRedis(Properties props) { + super(props); + } + + public SaTokenDaoOfRedis(RedisClient redisClient) { + super(redisClient); + } +} \ No newline at end of file diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisBase64.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisBase64.java new file mode 100644 index 00000000..bca0e62f --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisBase64.java @@ -0,0 +1,186 @@ +package cn.dev33.satoken.solon.dao; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.util.SaFoxUtil; +import org.noear.redisx.RedisClient; +import org.noear.redisx.plus.RedisBucket; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +/** + * SaTokenDao 的 redis 适配(可以完全精准还原所有序列化类型) + * + * @author noear + * @since 1.6 + */ +public class SaTokenDaoOfRedisBase64 implements SaTokenDao { + private final RedisBucket redisBucket; + + public SaTokenDaoOfRedisBase64(Properties props) { + this(new RedisClient(props)); + } + + public SaTokenDaoOfRedisBase64(RedisClient redisClient) { + redisBucket = redisClient.getBucket(); + } + + + /** + * 获取Value,如无返空 + */ + @Override + public String get(String key) { + return redisBucket.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) { + redisBucket.store(key, value, (int) SaTokenDao.NEVER_EXPIRE); + } else { + redisBucket.store(key, value, (int) timeout); + } + } + + /** + * 修改指定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) { + redisBucket.remove(key); + } + + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + return redisBucket.ttl(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; + } + redisBucket.delay(key, (int) timeout); + } + + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return redisBucket.getAndDeserialize(key); + } + + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + // 判断是否为永不过期 + if (timeout == SaTokenDao.NEVER_EXPIRE) { + redisBucket.storeAndSerialize(key, object); + } else { + redisBucket.storeAndSerialize(key, object, (int) timeout); + } + } + + /** + * 更新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) { + redisBucket.remove(key); + } + + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + return redisBucket.ttl(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; + } + redisBucket.delay(key, (int) timeout); + } + + + /** + * 搜索数据 + */ + @Override + 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, sortType); + } +} \ No newline at end of file diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisJson.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisJson.java new file mode 100644 index 00000000..fdddbb03 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisJson.java @@ -0,0 +1,199 @@ +package cn.dev33.satoken.solon.dao; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaFoxUtil; +import org.noear.redisx.RedisClient; +import org.noear.redisx.plus.RedisBucket; +import org.noear.snack.ONode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +/** + * SaTokenDao 的 redis 适配(基于json序列化,不能完全精准还原所有类型) + * + * @author noear + * @since 1.6 + */ +public class SaTokenDaoOfRedisJson implements SaTokenDao { + private final RedisBucket redisBucket; + + public SaTokenDaoOfRedisJson(Properties props) { + this(new RedisClient(props)); + } + + public SaTokenDaoOfRedisJson(RedisClient redisClient) { + redisBucket = redisClient.getBucket(); + + // 重写 SaSession 生成策略 + SaStrategy.me.createSession = (sessionId) -> new SaSessionForJson(sessionId); + + } + + @Override + public SaSession getSession(String sessionId) { + Object obj = getObject(sessionId); + if (obj == null) { + return null; + } + return ONode.deserialize(obj.toString(), SaSessionForJson.class); + } + + + /** + * 获取Value,如无返空 + */ + @Override + public String get(String key) { + return redisBucket.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) { + redisBucket.store(key, value, (int) SaTokenDao.NEVER_EXPIRE); + } else { + redisBucket.store(key, value, (int) timeout); + } + } + + /** + * 修改指定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) { + redisBucket.remove(key); + } + + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + return redisBucket.ttl(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; + } + redisBucket.delay(key, (int) timeout); + } + + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return get(key); + } + + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + + String value = ONode.serialize(object); + set(key, value, timeout); + } + + /** + * 更新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) { + redisBucket.remove(key); + } + + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + return redisBucket.ttl(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; + } + redisBucket.delay(key, (int) timeout); + } + + + /** + * 搜索数据 + */ + @Override + 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, sortType); + } +} \ No newline at end of file diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/json/SaJsonTemplateForSnack3.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/json/SaJsonTemplateForSnack3.java new file mode 100644 index 00000000..122c055f --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/json/SaJsonTemplateForSnack3.java @@ -0,0 +1,22 @@ +package cn.dev33.satoken.solon.json; + +import cn.dev33.satoken.json.SaJsonTemplate; +import org.noear.snack.ONode; + +import java.util.Map; + +/** + * @author noear + * @since 2.0 + */ +public class SaJsonTemplateForSnack3 implements SaJsonTemplate { + @Override + public String toJsonString(Object o) { + return ONode.stringify(o); + } + + @Override + public Map parseJsonToMap(String s) { + return ONode.deserialize(s, Map.class); + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/oauth2/SaOAuth2AutoConfigure.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/oauth2/SaOAuth2AutoConfigure.java index 9b6bbc42..7805e0ed 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/oauth2/SaOAuth2AutoConfigure.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/oauth2/SaOAuth2AutoConfigure.java @@ -5,6 +5,7 @@ import cn.dev33.satoken.oauth2.config.SaOAuth2Config; import cn.dev33.satoken.oauth2.logic.SaOAuth2Template; import cn.dev33.satoken.oauth2.logic.SaOAuth2Util; import org.noear.solon.annotation.Bean; +import org.noear.solon.annotation.Condition; import org.noear.solon.annotation.Configuration; import org.noear.solon.annotation.Inject; @@ -12,13 +13,14 @@ import org.noear.solon.annotation.Inject; * @author noear * @since 2.0 */ +@Condition(onClass = SaOAuth2Manager.class) @Configuration public class SaOAuth2AutoConfigure { /** * 获取 OAuth2配置Bean */ @Bean - public SaOAuth2Config getConfig(@Inject(value = "${sa-token.oauth2}",required = false) SaOAuth2Config oAuth2Config) { + public SaOAuth2Config getConfig(@Inject(value = "${sa-token.oauth2}", required = false) SaOAuth2Config oAuth2Config) { return oAuth2Config; } diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/sso/SaSsoAutoConfigure.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/sso/SaSsoAutoConfigure.java index 7ec8fc2d..56edc176 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/sso/SaSsoAutoConfigure.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/sso/SaSsoAutoConfigure.java @@ -6,15 +6,15 @@ import cn.dev33.satoken.sso.SaSsoProcessor; import cn.dev33.satoken.sso.SaSsoTemplate; import cn.dev33.satoken.sso.SaSsoUtil; import org.noear.solon.annotation.Bean; +import org.noear.solon.annotation.Condition; import org.noear.solon.annotation.Configuration; -import org.noear.solon.annotation.Init; import org.noear.solon.annotation.Inject; -import org.noear.solon.core.AopContext; /** * @author noear * @since 2.0 */ +@Condition(onClass = SaSsoManager.class) @Configuration public class SaSsoAutoConfigure { /**