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集成...
零配置开箱即用,覆盖所有应用场景,你所需要的功能,这里都有