From 34f1e1f2db1fa5c537c319e6a2f09d0d280b8065 Mon Sep 17 00:00:00 2001 From: shengzhang <2393584716@qq.com> Date: Fri, 25 Dec 2020 00:16:12 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20=E5=AE=8C=E5=96=84v1.7.0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pj/satoken/SaTokenDaoRedis.java | 5 +- .../main/java/com/pj/test/TestController.java | 2 + sa-token-doc/doc/.nojekyll | 0 sa-token-doc/doc/README.md | 1 + sa-token-doc/doc/_sidebar.md | 1 + sa-token-doc/doc/fun/token-timeout.md | 45 ++++++++++++++++ sa-token-doc/doc/index.html | 9 ++-- sa-token-doc/doc/{ => lib}/index.css | 0 sa-token-doc/doc/start/download.md | 9 ++-- sa-token-doc/doc/start/example.md | 9 ++-- sa-token-doc/doc/use/config.md | 4 +- sa-token-doc/doc/use/dao-extend.md | 54 +++++++++++++------ sa-token-doc/doc/use/not-cookie.md | 12 ++--- sa-token-doc/index.html | 4 +- 14 files changed, 114 insertions(+), 41 deletions(-) delete mode 100644 sa-token-doc/doc/.nojekyll create mode 100644 sa-token-doc/doc/fun/token-timeout.md rename sa-token-doc/doc/{ => lib}/index.css (100%) diff --git a/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenDaoRedis.java b/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenDaoRedis.java index 52c1f01d..ecfb9709 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenDaoRedis.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenDaoRedis.java @@ -7,6 +7,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.stereotype.Component; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.session.SaSession; @@ -14,7 +15,7 @@ import cn.dev33.satoken.session.SaSession; /** * sa-token持久层的实现类 , 基于redis */ -//@Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token与redis的集成 +@Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token与redis的集成 public class SaTokenDaoRedis implements SaTokenDao { @@ -57,7 +58,6 @@ public class SaTokenDaoRedis implements SaTokenDao { if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键 return; } -// stringRedisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS); this.setValue(key, value, expire); } @@ -99,7 +99,6 @@ public class SaTokenDaoRedis implements SaTokenDao { if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键 return; } -// redisTemplate.opsForValue().set(session.getId(), session, expire, TimeUnit.SECONDS); this.saveSession(session, expire); } diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java index 28f7a485..5aae6404 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java @@ -112,6 +112,8 @@ public class TestController { public AjaxJson atCheck() { System.out.println("======================= 进入方法,测试注解鉴权接口 ========================= "); System.out.println("只有通过注解鉴权,才能进入此方法"); + StpUtil.checkActivityTimeout(); + StpUtil.updateLastActivityToNow(); return AjaxJson.getSuccess(); } diff --git a/sa-token-doc/doc/.nojekyll b/sa-token-doc/doc/.nojekyll deleted file mode 100644 index e69de29b..00000000 diff --git a/sa-token-doc/doc/README.md b/sa-token-doc/doc/README.md index 0f38702c..a497595e 100644 --- a/sa-token-doc/doc/README.md +++ b/sa-token-doc/doc/README.md @@ -58,6 +58,7 @@ StpUtil.checkLogin(); - ⚡ **无cookie模式** —— APP、小程序等前后台分离场景 - ⚡ **注解式鉴权** —— 优雅的将鉴权与业务代码分离 - ⚡ **花式token生成** —— 内置六种token风格,还可自定义token生成策略 +- ⚡ **自动续签** —— 提供两种token过期策略,灵活搭配使用,还可自动续签 - ⚡ **组件自动注入** —— 零配置与Spring等框架集成 - ⚡ **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流 diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index ea914d70..3819b545 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -25,6 +25,7 @@ - **附录** - [未登录场景值](/fun/not-login-scene) + - [token有效期详解](/fun/token-timeout) diff --git a/sa-token-doc/doc/fun/token-timeout.md b/sa-token-doc/doc/fun/token-timeout.md new file mode 100644 index 00000000..2d201ce7 --- /dev/null +++ b/sa-token-doc/doc/fun/token-timeout.md @@ -0,0 +1,45 @@ +# token有效期详解 + + + +`sa-token` 提供两种token自动过期策略,分别是`timeout`与`activity-timeout`,其详细用法如下: + + +### timeout +- `timeout`代表token的长久有效期,单位/秒,例如将其配置为`2592000`(30天),代表在30天后,token必定过期,无法继续使用 +- `timeout`无法续签,想要继续使用必须重新登录 +- `timeout`的值配置为-1后,代表永久有效,不会过期 + + +### activity-timeout +- `activity-timeout`代表临时有效期,单位/秒,例如将其配置为`1800`(30分钟),代表用户如果30分钟无操作,则此token会立即过期 +- 如果在30分钟内用户有操作,则会再次续签30分钟,用户如果一直操作则会一直续签,直到连续30分钟无操作,token才会过期 +- `activity-timeout`的值配置为-1后,代表永久有效,不会过期,此时也无需频繁续签 + + +### 关于activity-timeout的续签 +如果`activity-timeout`配置了大于零的值,`sa-token`会在登录时开始计时,在每次直接或间接调用`getLoginId()`时进行一次过期检查与续签操作。 +此时会有两种情况: +- 一种是会话无操作时间太长,token已经过期,此时框架会抛出`NotLoginException`异常(场景值=-3), +- 另一种则是会话在`activity-timeout`有效期内通过检查,此时token可以成功续签 + + +### 我可以手动续签吗? +**可以!** +如果框架的自动续签算法无法满足您的业务需求,你可以进行手动续签,`sa-token`提供两个API供你操作: +- `StpUtil.checkActivityTimeout()`: 检查当前token 是否已经[临时过期],如果已经过期则抛出异常 +- `StpUtil.updateLastActivityToNow()`: 续签当前token:(将 [最后操作时间] 更新为当前时间戳) +- 注意:在手动续签时,即时token已经 [临时过期] 也可续签成功,如果此场景下需要提示续签失败,可采用先检查再续签的形式保证token有效性 +- 例如以下代码: +``` java + // 先检查是否已过期 + StpUtil.checkActivityTimeout(); + // 检查通过后继续续签 + StpUtil.updateLastActivityToNow(); +``` + + +### timeout与activity-timeout可以同时使用吗? +**可以同时使用!** +两者的认证逻辑彼此独立,互不干扰,可以同时使用。 + diff --git a/sa-token-doc/doc/index.html b/sa-token-doc/doc/index.html index 9aab6a6a..8376e0c0 100644 --- a/sa-token-doc/doc/index.html +++ b/sa-token-doc/doc/index.html @@ -7,9 +7,9 @@ - + - + @@ -59,11 +59,12 @@ function(hook, vm) { // 解析之后执行 hook.afterEach(function(html) { - var url = 'https://github.com/click33/sa-token/tree/master/sa-token-doc/doc/' + vm.route.file; + var url = 'https://gitee.com/sz6/sa-token/tree/dev/sa-token-doc/doc/' + vm.route.file; + var url2 = 'https://github.com/click33/sa-token/tree/dev/sa-token-doc/doc/' + vm.route.file; var footer = [ '







', '' ].join(''); return html + footer; diff --git a/sa-token-doc/doc/index.css b/sa-token-doc/doc/lib/index.css similarity index 100% rename from sa-token-doc/doc/index.css rename to sa-token-doc/doc/lib/index.css diff --git a/sa-token-doc/doc/start/download.md b/sa-token-doc/doc/start/download.md index 1971902c..df09df42 100644 --- a/sa-token-doc/doc/start/download.md +++ b/sa-token-doc/doc/start/download.md @@ -22,16 +22,17 @@ - gitee地址:[https://gitee.com/sz6/sa-token](https://gitee.com/sz6/sa-token) - 开源不易,求鼓励,给个`star`吧 - 源码目录介绍 - - sa-token-dev: 源码 - - sa-token-demo-springboot: springboot集成示例 - - sa-token-doc: 文档介绍 + - `sa-token-dev`: 源码 + - `sa-token-spring-boot-starter`: springboot插件化集成 + - `sa-token-demo-springboot`: springboot集成示例 + - `sa-token-doc`: 文档介绍 ## jar包下载 [点击下载:sa-token-1.6.0.jar](https://oss.dev33.cn/sa-token/sa-token-1.6.0.jar) - +(注意:当前仅提供`v1.6.0`版本jar包下载,更多版本请前往maven中央仓库获取) diff --git a/sa-token-doc/doc/start/example.md b/sa-token-doc/doc/start/example.md index 4a7846b8..6f7c0cc5 100644 --- a/sa-token-doc/doc/start/example.md +++ b/sa-token-doc/doc/start/example.md @@ -23,7 +23,7 @@ ``` #### 3、配置文件 -- 你可以零配置启动项目 +- 你可以**零配置启动项目** - 但同时你也可以在`application.yml`中增加如下配置,定制性使用框架: ``` java @@ -32,8 +32,10 @@ spring: sa-token: # token名称 (同时也是cookie名称) token-name: satoken - # token有效期,单位s 默认30天 + # token有效期,单位s 默认30天, -1代表永不过期 timeout: 2592000 + # token临时有效期, 默认-1 代表不限制 + activity-timeout: -1 # 在多人登录同一账号时,是否共享会话 (为true时共用一个,为false时新登录挤掉旧登录) is-share: true # 是否尝试从请求体里读取token @@ -42,6 +44,8 @@ spring: is-read-head: true # 是否尝试从cookie里读取token is-read-cookie: true + # token风格 + token-style: uuid # 是否在初始化配置时打印版本字符画 is-v: true ``` @@ -53,7 +57,6 @@ spring: 在项目中新建包 `com.pj` ,在此包内新建主类 `SaTokenDemoApplication.java`,输入以下代码: ``` java -@SaTokenSetup // 标注启动 sa-token @SpringBootApplication public class SaTokenDemoApplication { public static void main(String[] args) throws JsonProcessingException { diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index fc3bf31d..9d3527cb 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -70,8 +70,8 @@ spring: | 参数名称 | 类型 | 默认值 | 说明 | | :-------- | :-------- | :-------- | :-------- | | tokenName | String | satoken | token名称(同时也是cookie名称) | -| timeout | long | 2592000 | token有效期,单位/秒 默认30天,-1代表永久有效 | -| activityTimeout | long | -1 | token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒, 默认-1 代表不限制 (例如可以设置为1800代表30分钟内无操作就过期) | +| timeout | long | 2592000 | token有效期,单位/秒 默认30天,-1代表永久有效 [参考:token有效期详解](/fun/token-timeout) | +| activityTimeout | long | -1 | token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒, 默认-1 代表不限制 (例如可以设置为1800代表30分钟内无操作就过期) [参考:token有效期详解](/fun/token-timeout) | | isShare | Boolean | true | 在多人登录同一账号时,是否共享会话(为true时共用一个,为false时新登录挤掉旧登录) | | isReadBody | Boolean | true | 是否尝试从请求体里读取token | | isReadHead | Boolean | true | 是否尝试从header里读取token | diff --git a/sa-token-doc/doc/use/dao-extend.md b/sa-token-doc/doc/use/dao-extend.md index 2c134b14..d9721bd1 100644 --- a/sa-token-doc/doc/use/dao-extend.md +++ b/sa-token-doc/doc/use/dao-extend.md @@ -1,7 +1,6 @@ # 持久层扩展 --- -- 每次重启项目就得重新登录一遍,我想把登录数据都放在`redis`里,这样重启项目也不用重新登录,行不行? -- 行! +- 每次重启项目就得重新登录一遍,我想把登录数据都放在`redis`里,这样重启项目也不用重新登录,行不行?**行!** - 你需要做的就是重写`sa-token`的dao层实现方式,参考以下方案: @@ -22,7 +21,6 @@ - 代码参考: ```java - package com.pj.satoken; import java.util.concurrent.TimeUnit; @@ -68,56 +66,78 @@ public class SaTokenDaoRedis implements SaTokenDao { // 写入指定key-value键值对,并设定过期时间(单位:秒) @Override public void setValue(String key, String value, long timeout) { - stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS); + // 判断是否为永不过期 + if(timeout == SaTokenDao.NEVER_EXPIRE) { + stringRedisTemplate.opsForValue().set(key, value); + } else { + stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS); + } } // 更新指定key-value键值对 (过期时间取原来的值) @Override public void updateValue(String key, String value) { - long expire = redisTemplate.getExpire(key); - if(expire == -2) { // -2 = 无此键 + long expire = getTimeout(key); + if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键 return; } - stringRedisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS); + this.setValue(key, value, expire); } // 删除一个指定的key @Override - public void delKey(String key) { + public void deleteKey(String key) { stringRedisTemplate.delete(key); } + // 获取指定key的剩余存活时间 (单位: 秒) + @Override + public long getTimeout(String key) { + return stringRedisTemplate.getExpire(key); + } + + // 根据指定key的session,如果没有,则返回空 @Override - public SaSession getSaSession(String sessionId) { + public SaSession getSession(String sessionId) { return redisTemplate.opsForValue().get(sessionId); } // 将指定session持久化 @Override - public void saveSaSession(SaSession session, long timeout) { - redisTemplate.opsForValue().set(session.getId(), session, timeout, TimeUnit.SECONDS); + public void saveSession(SaSession session, long timeout) { + // 判断是否为永不过期 + if(timeout == SaTokenDao.NEVER_EXPIRE) { + redisTemplate.opsForValue().set(session.getId(), session); + } else { + redisTemplate.opsForValue().set(session.getId(), session, timeout, TimeUnit.SECONDS); + } } // 更新指定session @Override - public void updateSaSession(SaSession session) { - long expire = redisTemplate.getExpire(session.getId()); - if(expire == -2) { // -2 = 无此键 + public void updateSession(SaSession session) { + long expire = getSessionTimeout(session.getId()); + if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键 return; } - redisTemplate.opsForValue().set(session.getId(), session, expire, TimeUnit.SECONDS); + this.saveSession(session, expire); } // 删除一个指定的session @Override - public void deleteSaSession(String sessionId) { + public void deleteSession(String sessionId) { redisTemplate.delete(sessionId); } -} + // 获取指定SaSession的剩余存活时间 (单位: 秒) + @Override + public long getSessionTimeout(String sessionId) { + return redisTemplate.getExpire(sessionId); + } +} ``` diff --git a/sa-token-doc/doc/use/not-cookie.md b/sa-token-doc/doc/use/not-cookie.md index 4686f72c..12d62254 100644 --- a/sa-token-doc/doc/use/not-cookie.md +++ b/sa-token-doc/doc/use/not-cookie.md @@ -1,7 +1,7 @@ # 无cookie模式 --- -## 何为无cookie +### 何为无cookie - 常规PC端鉴权方法,一般由`cookie`进行 - 而`cookie`有两个特性:1、可由后端控制写入,2、每次请求自动提交 @@ -12,14 +12,14 @@ - 每次请求不能自动提交了,那就手动提交(难点在前端如何**将token传递到后端**,同时后端**将其读取出来**) -## 将token传递到前端 +### 将token传递到前端 1. 首先调用 `StpUtil.setLoginId(Object loginId)` 进行登录 2. 调用 `StpUtil.getTokenInfo()` 返回当前会话的token值 - - 此方法返回一个Map,有两个key:`tokenName`和`tokenValue`(`token`的名称和`token`的值) - - 将此Map传递到前台,让前端人员将这两个值保存到本地 + - 此方法返回一个对象,其有两个关键属性:`tokenName`和`tokenValue`(`token`的名称和`token`的值) + - 将此对象传递到前台,让前端人员将这两个值保存到本地 -## 前端将token提交到后端 +### 前端将token提交到后端 1. 无论是app还是小程序,其传递方式都大同小异 2. 那就是,将`token`塞到请求`header`里 ,格式为:`{tokenName: tokenValue}` 3. 以经典跨端框架`uni-app`为例: @@ -76,7 +76,7 @@ - 你当然不能每个`ajax`都写这么一坨,因为这种重复代码都是要封装在一个函数里统一调用的 -## 其它解决方案? +### 其它解决方案? - 如果你对`cookie`非常了解,那你就会明白,所谓`cookie`,本质上就是一个特殊的`header`参数而已, - 而既然它只是一个`header`参数,我们就能就能手动模拟实现它,从而完成鉴权操作 - 这其实是对无`cookie`模式的另一种解决方案,有兴趣的同学可以百度了解一下,在此暂不赘述 diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 17390b9e..8f192f81 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -7,7 +7,7 @@ - + @@ -46,7 +46,7 @@

sa-tokenv1.7.0

一个JavaWeb轻量级权限认证框架,功能全面,上手简单
-

登录验证、权限验证、自定义session会话、踢人下线、持久层扩展、无cookie模式、模拟他人账号、多账号体系、注解式鉴权、花式token、Spring集成...

+

登录验证、权限验证、自定义session会话、踢人下线、持久层扩展、无cookie模式、模拟他人账号、多账号体系、注解式鉴权、花式token、自动续签、Spring集成...

零配置开箱即用,覆盖所有应用场景,你所需要的功能,这里都有

GitHub