Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 128ab7614e | |||
| 7f0a3aa1c6 | |||
| 69d01e3e6e | |||
| 82ee90f712 | |||
| 9733c8777a | |||
| 4ff6a87ef5 | |||
| 7ffe6cb0e6 | |||
| dbba90d846 | |||
| 064ef4f12c | |||
| a8688cc07f | |||
| 4678e34203 | |||
| 81c0200981 | |||
| 2c6e656834 | |||
| 5ec35cce28 | |||
| 453d83cea4 | |||
| 0091fbad09 | |||
| 13760ccf4d | |||
| d9e2d98390 | |||
| 47140cea07 | |||
| 43308bf593 | |||
| d3792ad286 | |||
| 930c28df6d | |||
| a59ee9408b | |||
| 20f6bd7b3d | |||
| 67abf576f0 | |||
| 72252ab6b4 | |||
| 60e2afe76f | |||
| 62bd2febd0 | |||
| 434049c4a3 | |||
| 6277a1841b | |||
| 97ad4a783b | |||
| a503828e23 | |||
| 52abba6a98 | |||
| ebe6b0917b | |||
| 4b1370e603 |
@@ -8,5 +8,6 @@ unpackage/
|
||||
.project
|
||||
|
||||
.factorypath
|
||||
/.factorypath
|
||||
|
||||
.idea/
|
||||
@@ -1,11 +1,11 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://gitee.com/sz6/sa-token/raw/master/sa-token-doc/doc/logo.png" width="150" height="150" style="margin-bottom: 10px;">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.7.0</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.9.0</h1>
|
||||
<h4 align="center">一个JavaWeb轻量级权限认证框架,功能全面,上手简单</h4>
|
||||
<h4 align="center">
|
||||
<a href="https://gitee.com/sz6/sa-token/stargazers"><img src="https://gitee.com/sz6/sa-token/badge/star.svg"></a>
|
||||
<a href="https://github.com/click33/sa-token"><img src="https://img.shields.io/badge/sa--token-v1.7.0-2B9939"></a>
|
||||
<a href="https://github.com/click33/sa-token"><img src="https://img.shields.io/badge/sa--token-v1.9.0-2B9939"></a>
|
||||
<a href="https://github.com/click33/sa-token/stargazers"><img src="https://img.shields.io/github/stars/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/watchers"><img src="https://img.shields.io/github/watchers/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/network/members"><img src="https://img.shields.io/github/forks/click33/sa-token"></a>
|
||||
@@ -16,53 +16,76 @@
|
||||
---
|
||||
|
||||
|
||||
## 😘 在线资料
|
||||
- ##### [官网首页:http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
|
||||
- ##### [在线文档:http://sa-token.dev33.cn/doc/index.html](http://sa-token.dev33.cn/doc/index.html)
|
||||
- ##### [需求提交:我们深知一个优秀的项目需要海纳百川,点我在线提交需求](http://sa-app.dev33.cn/wall.html?name=sa-token)
|
||||
- ##### [开源不易,求鼓励,点个star吧](https://github.com/click33/sa-token)
|
||||
## 在线资料
|
||||
|
||||
- [官网首页:http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
|
||||
|
||||
- [在线文档:http://sa-token.dev33.cn/doc/index.html](http://sa-token.dev33.cn/doc/index.html)
|
||||
|
||||
- [需求提交:我们深知一个优秀的项目需要海纳百川,点我在线提交需求](http://sa-app.dev33.cn/wall.html?name=sa-token)
|
||||
|
||||
- [开源不易,求鼓励,点个star吧](https://github.com/click33/sa-token)
|
||||
|
||||
|
||||
## ⭐ sa-token是什么?
|
||||
- **sa-token是一个JavaWeb轻量级权限认证框架,其API调用非常简单,有多简单呢?以登录验证为例,你只需要:**
|
||||
## sa-token是什么?
|
||||
sa-token是一个JavaWeb轻量级权限认证框架,其API调用非常简单,有多简单呢?以登录验证为例,你只需要:
|
||||
|
||||
``` java
|
||||
// 在登录时写入当前会话的账号id
|
||||
StpUtil.setLoginId(10001);
|
||||
StpUtil.setLoginId(10001);
|
||||
|
||||
// 然后在任意需要校验登录处调用以下API --- 如果当前会话未登录,这句代码会抛出 `NotLoginException`异常
|
||||
StpUtil.checkLogin();
|
||||
```
|
||||
|
||||
|
||||
- **然后在任意需要验证登录权限的地方:**
|
||||
``` java
|
||||
// 检测是否登录 --- 如果当前会话未登录,下面这句代码会抛出 `NotLoginException`异常
|
||||
StpUtil.checkLogin();
|
||||
```
|
||||
没有复杂的封装!不要任何的配置!只需这两行简单的调用,即可轻松完成系统登录鉴权!
|
||||
|
||||
|
||||
- **没有复杂的封装!不要任何的配置!先写入,后鉴权!只需这两行简单的调用,即可轻松完成系统登录鉴权!**
|
||||
|
||||
|
||||
## 🔥 框架设计思想
|
||||
## 框架设计思想
|
||||
与其它权限认证框架相比,`sa-token`尽力保证两点:
|
||||
- 上手简单:能自动化的配置全部自动化,不让你费脑子
|
||||
- 功能强大:能涵盖的功能全部涵盖,不让你用个框架还要自己给框架打各种补丁
|
||||
|
||||
|
||||
## 💦️️ 涵盖功能
|
||||
- ⚡ **登录验证** —— 轻松登录鉴权,并提供五种细分场景值
|
||||
- ⚡ **权限验证** —— 拦截违规调用,不同角色不同授权
|
||||
- ⚡ **自定义session会话** —— 专业的数据缓存中心
|
||||
- ⚡ **踢人下线** —— 将违规用户立刻清退下线
|
||||
- ⚡ **模拟他人账号** —— 实时操作任意用户状态数据
|
||||
- ⚡ **持久层扩展** —— 可集成redis、MongoDB等专业缓存中间件
|
||||
- ⚡ **多账号认证体系** —— 比如一个商城项目的user表和admin表分开鉴权
|
||||
- ⚡ **无cookie模式** —— APP、小程序等前后台分离场景
|
||||
- ⚡ **注解式鉴权** —— 优雅的将鉴权与业务代码分离
|
||||
- ⚡ **花式token生成** —— 内置六种token风格,还可自定义token生成策略
|
||||
- ⚡ **组件自动注入** —— 零配置与Spring等框架集成
|
||||
- ⚡ **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流
|
||||
如果上面的示例能够证明`sa-token`的简单,那么以下API则可以证明`sa-token`的强大
|
||||
``` java
|
||||
StpUtil.setLoginId(10001); // 标记当前会话登录的账号id
|
||||
StpUtil.getLoginId(); // 获取当前会话登录的账号id
|
||||
StpUtil.isLogin(); // 获取当前会话是否已经登录, 返回true或false
|
||||
StpUtil.logout(); // 当前会话注销登录
|
||||
StpUtil.logoutByLoginId(10001); // 让账号为10001的会话注销登录(踢人下线)
|
||||
StpUtil.hasRole("super-admin"); // 查询当前账号是否含有指定角色标识, 返回true或false
|
||||
StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指定权限, 返回true或false
|
||||
StpUtil.getSession(); // 获取当前账号id的Session
|
||||
StpUtil.getSessionByLoginId(10001); // 获取账号id为10001的Session
|
||||
StpUtil.getTokenValueByLoginId(10001); // 获取账号id为10001的token令牌值
|
||||
StpUtil.setLoginId(10001, "PC"); // 指定设备标识登录
|
||||
StpUtil.logoutByLoginId(10001, "PC"); // 指定设备标识进行强制注销 (不同端不受影响)
|
||||
```
|
||||
sa-token的API众多,请恕此处无法为您逐一展示,更多示例请戳官方在线文档
|
||||
|
||||
|
||||
## 🔨 贡献代码
|
||||
|
||||
|
||||
## 涵盖功能
|
||||
- **登录验证** —— 轻松登录鉴权,并提供五种细分场景值
|
||||
- **权限验证** —— 拦截违规调用,不同角色不同授权
|
||||
- **Session会话** —— 专业的数据缓存中心
|
||||
- **踢人下线** —— 将违规用户立刻清退下线
|
||||
- **模拟他人账号** —— 实时操作任意用户状态数据
|
||||
- **持久层扩展** —— 可集成redis、MongoDB等专业缓存中间件
|
||||
- **多账号认证体系** —— 比如一个商城项目的user表和admin表分开鉴权
|
||||
- **无Cookie模式** —— APP、小程序等前后台分离场景
|
||||
- **注解式鉴权** —— 优雅的将鉴权与业务代码分离
|
||||
- **花式token生成** —— 内置六种token风格,还可自定义token生成策略
|
||||
- **自动续签** —— 提供两种token过期策略,灵活搭配使用,还可自动续签
|
||||
- **同端互斥登录** —— 像QQ一样手机电脑同时在线,但是两个手机上互斥登录
|
||||
- **组件自动注入** —— 零配置与Spring等框架集成
|
||||
- **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流
|
||||
|
||||
|
||||
## 贡献代码
|
||||
sa-token欢迎大家贡献代码,为框架添砖加瓦
|
||||
1. 在github上fork一份到自己的仓库
|
||||
2. clone自己的仓库到本地电脑
|
||||
@@ -71,7 +94,7 @@ sa-token欢迎大家贡献代码,为框架添砖加瓦
|
||||
5. 等待合并
|
||||
|
||||
|
||||
## 🌱 建议贡献的地方
|
||||
## 建议贡献的地方
|
||||
- 修复源码现有bug,或增加新的实用功能
|
||||
- 完善在线文档,或者修复现有错误之处
|
||||
- 更多demo示例:比如SSM版搭建步骤
|
||||
@@ -79,11 +102,11 @@ sa-token欢迎大家贡献代码,为框架添砖加瓦
|
||||
- 如果更新实用功能,可在文档友情链接处留下自己的推广链接
|
||||
|
||||
|
||||
## 🚀 友情链接
|
||||
## 友情链接
|
||||
[**[ okhttps ]** 一个轻量级http通信框架,支持 WebSocket 以及 Stomp 协议](https://gitee.com/ejlchina-zhxu/okhttps)
|
||||
|
||||
|
||||
## 😎 交流群
|
||||
## 交流群
|
||||
QQ交流群:[1002350610 点击加入](https://jq.qq.com/?_wv=1027&k=45H977HM) ,欢迎你的加入
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.7.0</version>
|
||||
<version>1.9.0</version>
|
||||
|
||||
<!-- 项目介绍 -->
|
||||
<name>sa-token</name>
|
||||
@@ -18,8 +18,10 @@
|
||||
|
||||
<!-- 所有模块 -->
|
||||
<modules>
|
||||
<module>sp-token-core</module>
|
||||
<module>sa-token-core</module>
|
||||
<module>sa-token-spring-boot-starter</module>
|
||||
<module>sa-token-dao-redis</module>
|
||||
<module>sa-token-dao-redis-jackson</module>
|
||||
</modules>
|
||||
|
||||
<!-- 开源协议 apache 2.0 -->
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<version>1.9.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
+4
-1
@@ -15,7 +15,7 @@ import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
|
||||
/**
|
||||
* 管理sa-token所有对象
|
||||
* 管理sa-token所有接口对象
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -55,6 +55,9 @@ public class SaTokenManager {
|
||||
return saTokenDao;
|
||||
}
|
||||
public static void setSaTokenDao(SaTokenDao saTokenDao) {
|
||||
if(SaTokenManager.saTokenDao != null && (SaTokenManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
|
||||
((SaTokenDaoDefaultImpl)SaTokenManager.saTokenDao).endRefreshTimer();
|
||||
}
|
||||
SaTokenManager.saTokenDao = saTokenDao;
|
||||
}
|
||||
public synchronized static void initSaTokenDao() {
|
||||
+7
-3
@@ -1,15 +1,19 @@
|
||||
package cn.dev33.satoken.action;
|
||||
|
||||
/**
|
||||
* sa-token内置操作接口
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaTokenAction {
|
||||
|
||||
|
||||
/**
|
||||
* 生成一个token
|
||||
* @param loginId 账号id
|
||||
* @param loginKey 登录标识key
|
||||
* @param loginKey 账号标识key
|
||||
* @return 一个token
|
||||
*/
|
||||
public String createToken(Object loginId, String loginKey);
|
||||
|
||||
|
||||
|
||||
}
|
||||
+2
-2
@@ -40,11 +40,11 @@ public class SaTokenActionDefaultImpl implements SaTokenAction {
|
||||
else if(tokenStyle.equals("random-128")) {
|
||||
return SaTokenInsideUtil.getRandomString(128);
|
||||
}
|
||||
// tik风格
|
||||
// tik风格 (2_14_16)
|
||||
else if(tokenStyle.equals("tik")) {
|
||||
return SaTokenInsideUtil.getRandomString(2) + "_" + SaTokenInsideUtil.getRandomString(14) + "_" + SaTokenInsideUtil.getRandomString(16) + "__";
|
||||
}
|
||||
// 默认
|
||||
// 默认,还是uuid
|
||||
else {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
+2
-1
@@ -6,7 +6,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 标注一个路由方法,当前会话必须已登录才能通过
|
||||
* 标注一个路由方法,当前会话必须已登录才能通过
|
||||
* <p> 可标注在类上,其效果等同于标注在此类的所有方法上
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
+6
-17
@@ -7,6 +7,7 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 标注一个路由方法,当前会话必须具有指定权限才可以通过
|
||||
* <p> 可标注在类上,其效果等同于标注在此类的所有方法上
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -15,27 +16,15 @@ import java.lang.annotation.Target;
|
||||
public @interface SaCheckPermission {
|
||||
|
||||
/**
|
||||
* 权限码数组 ,String类型
|
||||
* @return .
|
||||
* 需要验证的权限码
|
||||
* @return 需要验证的权限码
|
||||
*/
|
||||
String [] value() default {};
|
||||
|
||||
/**
|
||||
* 权限码数组 ,int类型
|
||||
* @return .
|
||||
* 指定验证模式是AND还是OR,默认AND
|
||||
* @return 验证模式
|
||||
*/
|
||||
int [] valueInt() default {};
|
||||
|
||||
/**
|
||||
* 权限码数组 ,long类型
|
||||
* @return .
|
||||
*/
|
||||
long [] valueLong() default {};
|
||||
|
||||
/**
|
||||
* 是否属于and型验证 ,true=必须全部具有,false=只要具有一个就可以通过
|
||||
* @return .
|
||||
*/
|
||||
boolean isAnd() default true;
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* 标注一个路由方法,当前会话必须具有指定角色标识才可以通过
|
||||
* <p> 可标注在类上,其效果等同于标注在此类的所有方法上
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD,ElementType.TYPE})
|
||||
public @interface SaCheckRole {
|
||||
|
||||
/**
|
||||
* 需要验证的角色标识
|
||||
* @return 需要验证的权限码
|
||||
*/
|
||||
String [] value() default {};
|
||||
|
||||
/**
|
||||
* 指定验证模式是AND还是OR,默认AND
|
||||
* @return 验证模式
|
||||
*/
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package cn.dev33.satoken.annotation;
|
||||
|
||||
/**
|
||||
* 指定注解鉴权的验证模式
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public enum SaMode {
|
||||
|
||||
/**
|
||||
* 必须具有所有的选项
|
||||
*/
|
||||
AND,
|
||||
|
||||
/**
|
||||
* 只需具有其中一个选项
|
||||
*/
|
||||
OR
|
||||
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
package cn.dev33.satoken.config;
|
||||
|
||||
/**
|
||||
* sa-token 配置类Model
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenConfig {
|
||||
|
||||
/** token名称 (同时也是cookie名称) */
|
||||
private String tokenName = "satoken";
|
||||
|
||||
/** token有效期,单位/秒 默认30天, -1代表永久 */
|
||||
private long timeout = 30 * 24 * 60 * 60;
|
||||
|
||||
/** token临时有效期 (指定时间内无操作就视为token过期) 单位/秒, 默认-1 代表不限制 (例如可以设置为1800代表30分钟内无操作就过期) */
|
||||
private long activityTimeout = -1;
|
||||
|
||||
/** 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) */
|
||||
private Boolean allowConcurrentLogin = true;
|
||||
|
||||
/** 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) */
|
||||
private Boolean isShare = true;
|
||||
|
||||
/** 是否尝试从请求体里读取token */
|
||||
private Boolean isReadBody = true;
|
||||
|
||||
/** 是否尝试从header里读取token */
|
||||
private Boolean isReadHead = true;
|
||||
|
||||
/** 是否尝试从cookie里读取token */
|
||||
private Boolean isReadCookie = true;
|
||||
|
||||
/** token风格 */
|
||||
private String tokenStyle = "uuid";
|
||||
|
||||
/** 默认dao层实现类中,每次清理过期数据间隔的时间 (单位: 秒) ,默认值30秒,设置为-1代表不启动定时清理 */
|
||||
private int dataRefreshPeriod = 30;
|
||||
|
||||
/** 获取token专属session时是否必须登录 (如果配置为true,会在每次获取token专属session时校验是否登录) */
|
||||
private Boolean tokenSessionCheckLogin = true;
|
||||
|
||||
/** 是否在初始化配置时打印版本字符画 */
|
||||
private Boolean isV = true;
|
||||
|
||||
|
||||
/**
|
||||
* @return tokenName
|
||||
*/
|
||||
public String getTokenName() {
|
||||
return tokenName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tokenName 要设置的 tokenName
|
||||
*/
|
||||
public void setTokenName(String tokenName) {
|
||||
this.tokenName = tokenName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return timeout
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeout 要设置的 timeout
|
||||
*/
|
||||
public void setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return activityTimeout
|
||||
*/
|
||||
public long getActivityTimeout() {
|
||||
return activityTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param activityTimeout 要设置的 activityTimeout
|
||||
*/
|
||||
public void setActivityTimeout(long activityTimeout) {
|
||||
this.activityTimeout = activityTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return allowConcurrentLogin
|
||||
*/
|
||||
public Boolean getAllowConcurrentLogin() {
|
||||
return allowConcurrentLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allowConcurrentLogin 要设置的 allowConcurrentLogin
|
||||
*/
|
||||
public void setAllowConcurrentLogin(Boolean allowConcurrentLogin) {
|
||||
this.allowConcurrentLogin = allowConcurrentLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isShare
|
||||
*/
|
||||
public Boolean getIsShare() {
|
||||
return isShare;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isShare 要设置的 isShare
|
||||
*/
|
||||
public void setIsShare(Boolean isShare) {
|
||||
this.isShare = isShare;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isReadBody
|
||||
*/
|
||||
public Boolean getIsReadBody() {
|
||||
return isReadBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isReadBody 要设置的 isReadBody
|
||||
*/
|
||||
public void setIsReadBody(Boolean isReadBody) {
|
||||
this.isReadBody = isReadBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isReadHead
|
||||
*/
|
||||
public Boolean getIsReadHead() {
|
||||
return isReadHead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isReadHead 要设置的 isReadHead
|
||||
*/
|
||||
public void setIsReadHead(Boolean isReadHead) {
|
||||
this.isReadHead = isReadHead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isReadCookie
|
||||
*/
|
||||
public Boolean getIsReadCookie() {
|
||||
return isReadCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isReadCookie 要设置的 isReadCookie
|
||||
*/
|
||||
public void setIsReadCookie(Boolean isReadCookie) {
|
||||
this.isReadCookie = isReadCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return tokenStyle
|
||||
*/
|
||||
public String getTokenStyle() {
|
||||
return tokenStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tokenStyle 要设置的 tokenStyle
|
||||
*/
|
||||
public void setTokenStyle(String tokenStyle) {
|
||||
this.tokenStyle = tokenStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return dataRefreshPeriod
|
||||
*/
|
||||
public int getDataRefreshPeriod() {
|
||||
return dataRefreshPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dataRefreshPeriod 要设置的 dataRefreshPeriod
|
||||
*/
|
||||
public void setDataRefreshPeriod(int dataRefreshPeriod) {
|
||||
this.dataRefreshPeriod = dataRefreshPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return tokenSessionCheckLogin
|
||||
*/
|
||||
public Boolean getTokenSessionCheckLogin() {
|
||||
return tokenSessionCheckLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tokenSessionCheckLogin 要设置的 tokenSessionCheckLogin
|
||||
*/
|
||||
public void setTokenSessionCheckLogin(Boolean tokenSessionCheckLogin) {
|
||||
this.tokenSessionCheckLogin = tokenSessionCheckLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isV
|
||||
*/
|
||||
public Boolean getIsV() {
|
||||
return isV;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isV 要设置的 isV
|
||||
*/
|
||||
public void setIsV(Boolean isV) {
|
||||
this.isV = isV;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaTokenConfig [tokenName=" + tokenName + ", timeout=" + timeout + ", activityTimeout=" + activityTimeout
|
||||
+ ", allowConcurrentLogin=" + allowConcurrentLogin + ", isShare=" + isShare + ", isReadBody="
|
||||
+ isReadBody + ", isReadHead=" + isReadHead + ", isReadCookie=" + isReadCookie + ", tokenStyle="
|
||||
+ tokenStyle + ", dataRefreshPeriod=" + dataRefreshPeriod + ", tokenSessionCheckLogin="
|
||||
+ tokenSessionCheckLogin + ", isV=" + isV + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+3
-3
@@ -8,7 +8,7 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 创建一个配置文件
|
||||
* sa-token配置文件创建工厂类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -16,7 +16,7 @@ public class SaTokenConfigFactory {
|
||||
|
||||
|
||||
/**
|
||||
* 默认配置文件地址
|
||||
* 默认配置文件地址
|
||||
*/
|
||||
public static String configPath = "sa-token.properties";
|
||||
|
||||
@@ -102,7 +102,7 @@ public class SaTokenConfigFactory {
|
||||
* 将字符串转化为指定数据类型
|
||||
* @param str 值
|
||||
* @param cs 要转换的类型
|
||||
* @return .
|
||||
* @return 转化好的结果
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T>T getObjectByClass(String str, Class<T> cs){
|
||||
+19
-23
@@ -12,41 +12,37 @@ import javax.servlet.http.HttpServletResponse;
|
||||
public interface SaTokenCookie {
|
||||
|
||||
/**
|
||||
* 获取指定cookie .
|
||||
*
|
||||
* @param request .
|
||||
* @param cookieName .
|
||||
* @return .
|
||||
* 在request对象中获取指定Cookie
|
||||
* @param request request对象
|
||||
* @param cookieName Cookie名称
|
||||
* @return 查找到的Cookie对象
|
||||
*/
|
||||
public Cookie getCookie(HttpServletRequest request, String cookieName);
|
||||
|
||||
/**
|
||||
* 添加cookie
|
||||
*
|
||||
* @param response .
|
||||
* @param name .
|
||||
* @param value .
|
||||
* @param path .
|
||||
* @param timeout .
|
||||
* 添加Cookie
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
* @param value Cookie值
|
||||
* @param path Cookie路径
|
||||
* @param timeout 过期时间 (秒)
|
||||
*/
|
||||
public void addCookie(HttpServletResponse response, String name, String value, String path, int timeout);
|
||||
|
||||
/**
|
||||
* 删除cookie .
|
||||
*
|
||||
* @param request .
|
||||
* @param response .
|
||||
* @param name .
|
||||
* 删除Cookie
|
||||
* @param request request对象
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
*/
|
||||
public void delCookie(HttpServletRequest request, HttpServletResponse response, String name);
|
||||
|
||||
/**
|
||||
* 修改cookie的value值
|
||||
*
|
||||
* @param request .
|
||||
* @param response .
|
||||
* @param name .
|
||||
* @param value .
|
||||
* 修改Cookie的value值
|
||||
* @param request request对象
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
* @param value Cookie值
|
||||
*/
|
||||
public void updateCookie(HttpServletRequest request, HttpServletResponse response, String name, String value);
|
||||
|
||||
+4
@@ -14,6 +14,7 @@ public class SaTokenCookieDefaultImpl implements SaTokenCookie {
|
||||
/**
|
||||
* 获取指定cookie
|
||||
*/
|
||||
@Override
|
||||
public Cookie getCookie(HttpServletRequest request, String cookieName) {
|
||||
return SaTokenCookieUtil.getCookie(request, cookieName);
|
||||
}
|
||||
@@ -21,6 +22,7 @@ public class SaTokenCookieDefaultImpl implements SaTokenCookie {
|
||||
/**
|
||||
* 添加cookie
|
||||
*/
|
||||
@Override
|
||||
public void addCookie(HttpServletResponse response, String name, String value, String path, int timeout) {
|
||||
SaTokenCookieUtil.addCookie(response, name, value, path, timeout);
|
||||
}
|
||||
@@ -28,6 +30,7 @@ public class SaTokenCookieDefaultImpl implements SaTokenCookie {
|
||||
/**
|
||||
* 删除cookie
|
||||
*/
|
||||
@Override
|
||||
public void delCookie(HttpServletRequest request, HttpServletResponse response, String name) {
|
||||
SaTokenCookieUtil.delCookie(request, response, name);
|
||||
}
|
||||
@@ -35,6 +38,7 @@ public class SaTokenCookieDefaultImpl implements SaTokenCookie {
|
||||
/**
|
||||
* 修改cookie的value值
|
||||
*/
|
||||
@Override
|
||||
public void updateCookie(HttpServletRequest request, HttpServletResponse response, String name, String value) {
|
||||
SaTokenCookieUtil.updateCookie(request, response, name, value);
|
||||
}
|
||||
+21
-27
@@ -5,19 +5,16 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* cookie操作工具类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
* Cookie操作工具类
|
||||
* @author kong
|
||||
*/
|
||||
public class SaTokenCookieUtil {
|
||||
|
||||
/**
|
||||
* 获取指定cookie .
|
||||
*
|
||||
* @param request .
|
||||
* @param cookieName .
|
||||
* @return .
|
||||
* 在request对象中获取指定Cookie
|
||||
* @param request request对象
|
||||
* @param cookieName Cookie名称
|
||||
* @return 查找到的Cookie对象
|
||||
*/
|
||||
public static Cookie getCookie(HttpServletRequest request, String cookieName) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
@@ -32,13 +29,12 @@ public class SaTokenCookieUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加cookie
|
||||
*
|
||||
* @param response .
|
||||
* @param name .
|
||||
* @param value .
|
||||
* @param path .
|
||||
* @param timeout .
|
||||
* 添加cookie
|
||||
* @param response response
|
||||
* @param name Cookie名称
|
||||
* @param value Cookie值
|
||||
* @param path Cookie写入路径
|
||||
* @param timeout Cookie有效期 (秒)
|
||||
*/
|
||||
public static void addCookie(HttpServletResponse response, String name, String value, String path, int timeout) {
|
||||
Cookie cookie = new Cookie(name, value);
|
||||
@@ -51,11 +47,10 @@ public class SaTokenCookieUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除cookie .
|
||||
*
|
||||
* @param request .
|
||||
* @param response .
|
||||
* @param name .
|
||||
* 删除Cookie
|
||||
* @param request request对象
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
*/
|
||||
public static void delCookie(HttpServletRequest request, HttpServletResponse response, String name) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
@@ -70,12 +65,11 @@ public class SaTokenCookieUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改cookie的value值
|
||||
*
|
||||
* @param request .
|
||||
* @param response .
|
||||
* @param name .
|
||||
* @param value .
|
||||
* 修改cookie的value值
|
||||
* @param request request对象
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
* @param value Cookie值
|
||||
*/
|
||||
public static void updateCookie(HttpServletRequest request, HttpServletResponse response, String name,
|
||||
String value) {
|
||||
+23
-10
@@ -4,8 +4,7 @@ import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* sa-token持久层的接口
|
||||
* @author kong
|
||||
*
|
||||
* @author kong
|
||||
*/
|
||||
public interface SaTokenDao {
|
||||
|
||||
@@ -19,17 +18,17 @@ public interface SaTokenDao {
|
||||
|
||||
|
||||
/**
|
||||
* 根据key获取value ,如果没有,则返回空
|
||||
* 根据key获取value,如果没有,则返回空
|
||||
* @param key 键名称
|
||||
* @return value
|
||||
*/
|
||||
public String getValue(String key);
|
||||
|
||||
/**
|
||||
* 写入指定key-value键值对,并设定过期时间 (单位:秒)
|
||||
* 写入指定key-value键值对,并设定过期时间 (单位: 秒)
|
||||
* @param key 键名称
|
||||
* @param value 值
|
||||
* @param timeout 过期时间,单位:s
|
||||
* @param timeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public void setValue(String key, String value, long timeout);
|
||||
|
||||
@@ -53,18 +52,25 @@ public interface SaTokenDao {
|
||||
*/
|
||||
public long getTimeout(String key);
|
||||
|
||||
/**
|
||||
* 修改指定key的剩余存活时间 (单位: 秒)
|
||||
* @param key 指定key
|
||||
* @param timeout 过期时间
|
||||
*/
|
||||
public void updateTimeout(String key, long timeout);
|
||||
|
||||
|
||||
/**
|
||||
* 根据指定key的session,如果没有,则返回空
|
||||
* 根据指定key的Session,如果没有,则返回空
|
||||
* @param sessionId 键名称
|
||||
* @return SaSession
|
||||
*/
|
||||
public SaSession getSession(String sessionId);
|
||||
|
||||
/**
|
||||
* 将指定session持久化
|
||||
* 将指定Session持久化
|
||||
* @param session 要保存的session对象
|
||||
* @param timeout 过期时间,单位: s
|
||||
* @param timeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public void saveSession(SaSession session, long timeout);
|
||||
|
||||
@@ -81,12 +87,19 @@ public interface SaTokenDao {
|
||||
public void deleteSession(String sessionId);
|
||||
|
||||
/**
|
||||
* 获取指定SaSession的剩余存活时间 (单位: 秒)
|
||||
* 获取指定SaSession的剩余存活时间 (单位: 秒)
|
||||
* @param sessionId 指定SaSession
|
||||
* @return 这个SaSession的剩余存活时间
|
||||
* @return 这个SaSession的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
public long getSessionTimeout(String sessionId);
|
||||
|
||||
/**
|
||||
* 修改指定SaSession的剩余存活时间 (单位: 秒)
|
||||
* @param sessionId sessionId
|
||||
* @param timeout 过期时间
|
||||
*/
|
||||
public void updateSessionTimeout(String sessionId, long timeout);
|
||||
|
||||
|
||||
|
||||
|
||||
+82
-8
@@ -1,9 +1,15 @@
|
||||
package cn.dev33.satoken.dao;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.util.SaTaskUtil;
|
||||
import cn.dev33.satoken.util.SaTaskUtil.FunctionRunClass;
|
||||
|
||||
/**
|
||||
* sa-token持久层默认的实现类 , 基于内存Map
|
||||
@@ -11,17 +17,27 @@ import cn.dev33.satoken.session.SaSession;
|
||||
*
|
||||
*/
|
||||
public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
|
||||
|
||||
/**
|
||||
* 所有数据集合
|
||||
*/
|
||||
public Map<String, Object> dataMap = new HashMap<String, Object>();
|
||||
public Map<String, Object> dataMap = new ConcurrentHashMap<String, Object>();
|
||||
|
||||
/**
|
||||
* 过期时间集合 (单位: 毫秒) , 记录所有key的到期时间 [注意不是剩余存活时间]
|
||||
* 过期时间集合 (单位: 毫秒) , 记录所有key的到期时间 [注意不是剩余存活时间]
|
||||
*/
|
||||
public Map<String, Long> expireMap = new HashMap<String, Long>();
|
||||
public Map<String, Long> expireMap = new ConcurrentHashMap<String, Long>();
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
public SaTokenDaoDefaultImpl() {
|
||||
initRefreshTimer();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------ String 读写操作
|
||||
|
||||
@Override
|
||||
public String getValue(String key) {
|
||||
@@ -53,8 +69,15 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
public long getTimeout(String key) {
|
||||
return getKeyTimeout(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTimeout(String key, long timeout) {
|
||||
expireMap.put(key, System.currentTimeMillis() + timeout * 1000);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------ Session 读写操作
|
||||
|
||||
@Override
|
||||
public SaSession getSession(String sessionId) {
|
||||
clearKeyByTimeout(sessionId);
|
||||
@@ -86,9 +109,13 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
return getKeyTimeout(sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSessionTimeout(String sessionId, long timeout) {
|
||||
expireMap.put(sessionId, System.currentTimeMillis() + timeout * 1000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------------------
|
||||
// ------------------------ 过期时间相关操作
|
||||
|
||||
/**
|
||||
* 如果指定key已经过期,则立即清除它
|
||||
@@ -103,7 +130,6 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定key的剩余存活时间 (单位:秒)
|
||||
*/
|
||||
@@ -132,8 +158,56 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
}
|
||||
|
||||
|
||||
// --------------------- 定时清理过期数据
|
||||
|
||||
/**
|
||||
* 定时任务对象
|
||||
*/
|
||||
public Timer refreshTimer;
|
||||
|
||||
/**
|
||||
* 清理所有已经过期的key
|
||||
*/
|
||||
public void refreshDataMap() {
|
||||
Iterator<String> keys = expireMap.keySet().iterator();
|
||||
while (keys.hasNext()) {
|
||||
clearKeyByTimeout(keys.next());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化定时任务
|
||||
*/
|
||||
public void initRefreshTimer() {
|
||||
// 如果已经被初始化过了, 则停止它
|
||||
if(this.refreshTimer != null) {
|
||||
this.endRefreshTimer();
|
||||
}
|
||||
|
||||
// 开始新的定时任务
|
||||
if(SaTokenManager.getConfig().getDataRefreshPeriod() < 0) {
|
||||
return;
|
||||
}
|
||||
int period = SaTokenManager.getConfig().getDataRefreshPeriod() * 1000;
|
||||
this.refreshTimer = SaTaskUtil.setInterval(new FunctionRunClass() {
|
||||
@Override
|
||||
public void run() {
|
||||
refreshDataMap();
|
||||
}
|
||||
}, period, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束定时任务
|
||||
*/
|
||||
public void endRefreshTimer() {
|
||||
this.refreshTimer.cancel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+8
-17
@@ -4,14 +4,13 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 没有登陆抛出的异常
|
||||
* @author kong
|
||||
*
|
||||
* 一个异常:代表用户没有登录
|
||||
* @author kong
|
||||
*/
|
||||
public class NotLoginException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130142L;
|
||||
|
||||
@@ -59,7 +58,7 @@ public class NotLoginException extends RuntimeException {
|
||||
private String type;
|
||||
/**
|
||||
* 获取异常类型
|
||||
* @return
|
||||
* @return 异常类型
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
@@ -72,7 +71,7 @@ public class NotLoginException extends RuntimeException {
|
||||
private String loginKey;
|
||||
/**
|
||||
* 获得loginKey
|
||||
* @return login_key
|
||||
* @return loginKey
|
||||
*/
|
||||
public String getLoginKey() {
|
||||
return loginKey;
|
||||
@@ -81,16 +80,8 @@ public class NotLoginException extends RuntimeException {
|
||||
|
||||
|
||||
|
||||
// /**
|
||||
// * 创建一个
|
||||
// */
|
||||
// public NotLoginException() {
|
||||
// this(StpUtil.stpLogic.loginKey);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 创建一个
|
||||
* 构造方法创建一个
|
||||
* @param message 异常消息
|
||||
* @param loginKey loginKey
|
||||
* @param type 类型
|
||||
@@ -103,8 +94,8 @@ public class NotLoginException extends RuntimeException {
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态方法构建一个NotLoginException
|
||||
* @param loginKey loginKey
|
||||
* 静态方法构建一个NotLoginException
|
||||
* @param loginKey loginKey
|
||||
* @param type 场景类型
|
||||
* @return 构建完毕的异常对象
|
||||
*/
|
||||
+11
-12
@@ -8,41 +8,40 @@ import cn.dev33.satoken.stp.StpUtil;
|
||||
*
|
||||
*/
|
||||
public class NotPermissionException extends RuntimeException {
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130142L;
|
||||
|
||||
/**
|
||||
* 权限码
|
||||
*/
|
||||
private Object code;
|
||||
/** 权限码 */
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* @return 获得权限码
|
||||
*/
|
||||
public Object getCode() {
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* login_key
|
||||
* loginKey
|
||||
*/
|
||||
private String loginKey;
|
||||
/**
|
||||
* 获得login_key
|
||||
* @return login_key
|
||||
* 获得loginKey
|
||||
* @return loginKey
|
||||
*/
|
||||
public String getLoginKey() {
|
||||
return loginKey;
|
||||
}
|
||||
|
||||
|
||||
public NotPermissionException(Object code) {
|
||||
public NotPermissionException(String code) {
|
||||
this(code, StpUtil.stpLogic.loginKey);
|
||||
}
|
||||
public NotPermissionException(Object code, String loginKey) {
|
||||
// 这里到底要不要拼接上login_key呢?纠结
|
||||
public NotPermissionException(String code, String loginKey) {
|
||||
// 这里到底要不要拼接上loginKey呢?纠结
|
||||
super("无此权限:" + code);
|
||||
this.code = code;
|
||||
this.loginKey = loginKey;
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
/**
|
||||
* 没有指定角色标识,抛出的异常
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class NotRoleException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 8243974276159004739L;
|
||||
|
||||
/** 角色标识 */
|
||||
private String role;
|
||||
|
||||
/**
|
||||
* @return 获得角色标识
|
||||
*/
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
/**
|
||||
* loginKey
|
||||
*/
|
||||
private String loginKey;
|
||||
/**
|
||||
* 获得loginKey
|
||||
* @return loginKey
|
||||
*/
|
||||
public String getLoginKey() {
|
||||
return loginKey;
|
||||
}
|
||||
|
||||
|
||||
public NotRoleException(String role) {
|
||||
this(role, StpUtil.stpLogic.loginKey);
|
||||
}
|
||||
public NotRoleException(String role, String loginKey) {
|
||||
// 这里到底要不要拼接上loginKey呢?纠结
|
||||
super("无此角色:" + role);
|
||||
this.role = role;
|
||||
this.loginKey = loginKey;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+4
@@ -13,6 +13,10 @@ public class SaTokenException extends RuntimeException {
|
||||
private static final long serialVersionUID = 6806129545290130132L;
|
||||
|
||||
|
||||
/**
|
||||
* 构建一个异常
|
||||
* @param message 异常描述信息
|
||||
*/
|
||||
public SaTokenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
+3
-3
@@ -12,14 +12,14 @@ public interface SaTokenServlet {
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前请求的Request对象
|
||||
* 获取当前请求的 Request 对象
|
||||
* @return 当前请求的Request对象
|
||||
*/
|
||||
public HttpServletRequest getRequest();
|
||||
|
||||
/**
|
||||
* 获取当前会话的 response
|
||||
* @return 当前请求的response
|
||||
* 获取当前请求的 Response 对象
|
||||
* @return 当前请求的response对象
|
||||
*/
|
||||
public HttpServletResponse getResponse();
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* sa-token 对Servlet的相关操作 接口默认实现类
|
||||
* sa-token 对SaTokenServlet接口默认实现类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -0,0 +1,221 @@
|
||||
package cn.dev33.satoken.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
|
||||
|
||||
/**
|
||||
* session会话
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaSession implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 此会话的id */
|
||||
private String id;
|
||||
|
||||
/** 此会话的创建时间 */
|
||||
private long createTime;
|
||||
|
||||
/** 此会话的所有数据 */
|
||||
private Map<String, Object> dataMap = new ConcurrentHashMap<String, Object>();
|
||||
|
||||
/**
|
||||
* 构建一个 session对象
|
||||
*/
|
||||
public SaSession() {}
|
||||
|
||||
/**
|
||||
* 构建一个 session对象
|
||||
* @param id session的id
|
||||
*/
|
||||
public SaSession(String id) {
|
||||
this.id = id;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取此会话id
|
||||
* @return 此会话的id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前会话创建时间
|
||||
* @return 时间戳
|
||||
*/
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------- tokenSign相关
|
||||
|
||||
/**
|
||||
* 本session绑定的token签名列表
|
||||
*/
|
||||
private List<TokenSign> tokenSignList = new Vector<TokenSign>();
|
||||
|
||||
/**
|
||||
* 返回token签名列表
|
||||
* @return token签名列表
|
||||
*/
|
||||
public List<TokenSign> getTokenSignList() {
|
||||
return new Vector<>(tokenSignList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找一个token签名
|
||||
* @param tokenValue token值
|
||||
* @return 查找到的tokenSign
|
||||
*/
|
||||
public TokenSign getTokenSign(String tokenValue) {
|
||||
for (TokenSign tokenSign : getTokenSignList()) {
|
||||
if(tokenSign.getValue().equals(tokenValue)){
|
||||
return tokenSign;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 添加一个token签名
|
||||
* @param tokenSign token签名
|
||||
*/
|
||||
public void addTokenSign(TokenSign tokenSign) {
|
||||
// 如果已经存在于列表中,则无需再次添加
|
||||
for (TokenSign tokenSign2 : getTokenSignList()) {
|
||||
if(tokenSign2.getValue().equals(tokenSign.getValue())){
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 添加并更新
|
||||
tokenSignList.add(tokenSign);
|
||||
update();
|
||||
}
|
||||
/**
|
||||
* 移除一个token签名
|
||||
* @param tokenValue token名称
|
||||
*/
|
||||
public void removeTokenSign(String tokenValue) {
|
||||
TokenSign tokenSign = getTokenSign(tokenValue);
|
||||
if(tokenSignList.remove(tokenSign)) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------------- 存取值
|
||||
|
||||
/**
|
||||
* 写入一个值
|
||||
* @param key 名称
|
||||
* @param value 值
|
||||
*/
|
||||
public void setAttribute(String key, Object value) {
|
||||
dataMap.put(key, value);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取出一个值
|
||||
* @param key 名称
|
||||
* @return 值
|
||||
*/
|
||||
public Object getAttribute(String key) {
|
||||
return dataMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值,并指定取不到值时的默认值
|
||||
* @param key 名称
|
||||
* @param defaultValue 取不到值的时候返回的默认值
|
||||
* @return value
|
||||
*/
|
||||
public Object getAttribute(String key, Object defaultValue) {
|
||||
Object value = getAttribute(key);
|
||||
if(value != null) {
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个值
|
||||
* @param key 要移除的值的名字
|
||||
*/
|
||||
public void removeAttribute(String key) {
|
||||
dataMap.remove(key);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有值
|
||||
*/
|
||||
public void clearAttribute() {
|
||||
dataMap.clear();
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否含有指定key
|
||||
* @param key 是否含有指定值
|
||||
* @return 是否含有
|
||||
*/
|
||||
public boolean containsAttribute(String key) {
|
||||
return dataMap.keySet().contains(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前session会话所有key
|
||||
* @return 所有值的key列表
|
||||
*/
|
||||
public Set<String> attributeKeys() {
|
||||
return dataMap.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据集合(如果更新map里的值,请调用session.update()方法避免数据过时 )
|
||||
* @return 返回底层储存值的map对象
|
||||
*/
|
||||
public Map<String, Object> getDataMap() {
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------- 一些操作
|
||||
|
||||
/**
|
||||
* 将这个session从持久库更新一下
|
||||
*/
|
||||
public void update() {
|
||||
SaTokenManager.getSaTokenDao().updateSession(this);
|
||||
}
|
||||
|
||||
/** 注销会话(注销后,此session会话将不再存储服务器上) */
|
||||
public void logout() {
|
||||
SaTokenManager.getSaTokenDao().deleteSession(this.id);
|
||||
}
|
||||
|
||||
/** 如果这个token的tokenSign数量为零,则直接注销会话 */
|
||||
public void logoutByTokenSignCountToZero() {
|
||||
if(tokenSignList.size() == 0) {
|
||||
logout();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+12
-5
@@ -12,13 +12,20 @@ public class SaSessionCustomUtil {
|
||||
/**
|
||||
* 添加上指定前缀,防止恶意伪造session
|
||||
*/
|
||||
public static String session_key = "custom";
|
||||
public static String sessionKey = "custom";
|
||||
|
||||
/**
|
||||
* 组织一下自定义session的id
|
||||
* @param sessionId 会话id
|
||||
* @return sessionId
|
||||
*/
|
||||
public static String getSessionKey(String sessionId) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + session_key + ":session:" + sessionId;
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + sessionKey + ":session:" + sessionId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 指定key的session是否存在
|
||||
* 指定key的session是否存在
|
||||
* @param sessionId session的id
|
||||
* @return 是否存在
|
||||
*/
|
||||
@@ -27,7 +34,7 @@ public class SaSessionCustomUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定key的session
|
||||
* 获取指定key的session
|
||||
* @param sessionId key
|
||||
* @param isCreate 如果没有,是否新建并返回
|
||||
* @return SaSession
|
||||
@@ -51,7 +58,7 @@ public class SaSessionCustomUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定key的session
|
||||
* 删除指定key的session
|
||||
* @param sessionId 删除指定key
|
||||
*/
|
||||
public static void deleteSessionById(String sessionId) {
|
||||
@@ -0,0 +1,68 @@
|
||||
package cn.dev33.satoken.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 挂在到SaSession上的token签名
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class TokenSign implements Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1406115065849845073L;
|
||||
|
||||
/**
|
||||
* token值
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* 所在设备标识
|
||||
*/
|
||||
private String device;
|
||||
|
||||
|
||||
/** 构建一个 */
|
||||
public TokenSign() {}
|
||||
|
||||
/**
|
||||
* 构建一个
|
||||
* @param value token值
|
||||
* @param device 所在设备标识
|
||||
*/
|
||||
public TokenSign(String value, String device) {
|
||||
this.value = value;
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return value
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return device
|
||||
*/
|
||||
public String getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TokenSign [value=" + value + ", device=" + device + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+49
-28
@@ -28,14 +28,21 @@ public class SaTokenInfo {
|
||||
/** session剩余有效时间 (单位: 秒) */
|
||||
public long sessionTimeout;
|
||||
|
||||
/** token专属session剩余有效时间 (单位: 秒) */
|
||||
public long tokenSessionTimeout;
|
||||
|
||||
/**
|
||||
* token剩余无操作有效时间
|
||||
*/
|
||||
public long tokenActivityTimeout;
|
||||
|
||||
|
||||
/** 当前登录设备 */
|
||||
public String loginDevice;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return tokenName token名称
|
||||
* @return tokenName
|
||||
*/
|
||||
public String getTokenName() {
|
||||
return tokenName;
|
||||
@@ -43,11 +50,9 @@ public class SaTokenInfo {
|
||||
|
||||
/**
|
||||
* @param tokenName 要设置的 tokenName
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenInfo setTokenName(String tokenName) {
|
||||
public void setTokenName(String tokenName) {
|
||||
this.tokenName = tokenName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,11 +64,9 @@ public class SaTokenInfo {
|
||||
|
||||
/**
|
||||
* @param tokenValue 要设置的 tokenValue
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenInfo setTokenValue(String tokenValue) {
|
||||
public void setTokenValue(String tokenValue) {
|
||||
this.tokenValue = tokenValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,11 +78,9 @@ public class SaTokenInfo {
|
||||
|
||||
/**
|
||||
* @param isLogin 要设置的 isLogin
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenInfo setIsLogin(Boolean isLogin) {
|
||||
public void setIsLogin(Boolean isLogin) {
|
||||
this.isLogin = isLogin;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,11 +92,9 @@ public class SaTokenInfo {
|
||||
|
||||
/**
|
||||
* @param loginId 要设置的 loginId
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenInfo setLoginId(Object loginId) {
|
||||
public void setLoginId(Object loginId) {
|
||||
this.loginId = loginId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,13 +106,11 @@ public class SaTokenInfo {
|
||||
|
||||
/**
|
||||
* @param loginKey 要设置的 loginKey
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenInfo setLoginKey(String loginKey) {
|
||||
public void setLoginKey(String loginKey) {
|
||||
this.loginKey = loginKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return tokenTimeout
|
||||
*/
|
||||
@@ -123,11 +120,9 @@ public class SaTokenInfo {
|
||||
|
||||
/**
|
||||
* @param tokenTimeout 要设置的 tokenTimeout
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenInfo setTokenTimeout(long tokenTimeout) {
|
||||
public void setTokenTimeout(long tokenTimeout) {
|
||||
this.tokenTimeout = tokenTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,11 +134,23 @@ public class SaTokenInfo {
|
||||
|
||||
/**
|
||||
* @param sessionTimeout 要设置的 sessionTimeout
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenInfo setSessionTimeout(long sessionTimeout) {
|
||||
public void setSessionTimeout(long sessionTimeout) {
|
||||
this.sessionTimeout = sessionTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return tokenSessionTimeout
|
||||
*/
|
||||
public long getTokenSessionTimeout() {
|
||||
return tokenSessionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tokenSessionTimeout 要设置的 tokenSessionTimeout
|
||||
*/
|
||||
public void setTokenSessionTimeout(long tokenSessionTimeout) {
|
||||
this.tokenSessionTimeout = tokenSessionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,11 +162,23 @@ public class SaTokenInfo {
|
||||
|
||||
/**
|
||||
* @param tokenActivityTimeout 要设置的 tokenActivityTimeout
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenInfo setTokenActivityTimeout(long tokenActivityTimeout) {
|
||||
public void setTokenActivityTimeout(long tokenActivityTimeout) {
|
||||
this.tokenActivityTimeout = tokenActivityTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return loginDevice
|
||||
*/
|
||||
public String getLoginDevice() {
|
||||
return loginDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loginDevice 要设置的 loginDevice
|
||||
*/
|
||||
public void setLoginDevice(String loginDevice) {
|
||||
this.loginDevice = loginDevice;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,9 +188,11 @@ public class SaTokenInfo {
|
||||
public String toString() {
|
||||
return "SaTokenInfo [tokenName=" + tokenName + ", tokenValue=" + tokenValue + ", isLogin=" + isLogin
|
||||
+ ", loginId=" + loginId + ", loginKey=" + loginKey + ", tokenTimeout=" + tokenTimeout
|
||||
+ ", sessionTimeout=" + sessionTimeout + ", tokenActivityTimeout=" + tokenActivityTimeout + "]";
|
||||
+ ", sessionTimeout=" + sessionTimeout + ", tokenSessionTimeout=" + tokenSessionTimeout
|
||||
+ ", tokenActivityTimeout=" + tokenActivityTimeout + ", loginDevice=" + loginDevice + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 开放权限验证接口,方便重写
|
||||
* @author kong
|
||||
*/
|
||||
public interface StpInterface {
|
||||
|
||||
/**
|
||||
* 返回指定loginId所拥有的权限码集合
|
||||
* @param loginId 账号id
|
||||
* @param loginKey 具体的stp标识
|
||||
* @return 该账号id具有的权限码集合
|
||||
*/
|
||||
public List<String> getPermissionList(Object loginId, String loginKey);
|
||||
|
||||
/**
|
||||
* 返回指定loginId所拥有的角色标识集合
|
||||
* @param loginId 账号id
|
||||
* @param loginKey 具体的stp标识
|
||||
* @return 该账号id具有的角色标识集合
|
||||
*/
|
||||
public List<String> getRoleList(Object loginId, String loginKey);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 对StpInterface接口默认的实现类
|
||||
* @author kong
|
||||
*/
|
||||
public class StpInterfaceDefaultImpl implements StpInterface {
|
||||
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginKey) {
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginKey) {
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,443 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* 一个默认的实现
|
||||
* @author kong
|
||||
*/
|
||||
public class StpUtil {
|
||||
|
||||
/**
|
||||
* 底层的 StpLogic 对象
|
||||
*/
|
||||
public static StpLogic stpLogic = new StpLogic("login");
|
||||
|
||||
|
||||
// =================== 获取token 相关 ===================
|
||||
|
||||
/**
|
||||
* 返回token名称
|
||||
* @return 此StpLogic的token名称
|
||||
*/
|
||||
public static String getTokenName() {
|
||||
return stpLogic.getTokenName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前tokenValue
|
||||
* @return 当前tokenValue
|
||||
*/
|
||||
public static String getTokenValue() {
|
||||
return stpLogic.getTokenValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
*/
|
||||
public static String getLoginKey(){
|
||||
return stpLogic.getLoginKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的token信息
|
||||
* @return token信息
|
||||
*/
|
||||
public static SaTokenInfo getTokenInfo() {
|
||||
return stpLogic.getTokenInfo();
|
||||
}
|
||||
|
||||
|
||||
// =================== 登录相关操作 ===================
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
*/
|
||||
public static void setLoginId(Object loginId) {
|
||||
stpLogic.setLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
* @param device 设备标识
|
||||
*/
|
||||
public static void setLoginId(Object loginId, String device) {
|
||||
stpLogic.setLoginId(loginId, device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话注销登录
|
||||
*/
|
||||
public static void logout() {
|
||||
stpLogic.logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定token的会话注销登录
|
||||
* @param tokenValue 指定token
|
||||
*/
|
||||
public static void logoutByTokenValue(String tokenValue) {
|
||||
stpLogic.logoutByTokenValue(tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId的会话注销登录(踢人下线)
|
||||
* <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public static void logoutByLoginId(Object loginId) {
|
||||
stpLogic.logoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId指定设备的会话注销登录(踢人下线)
|
||||
* <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2
|
||||
* @param loginId 账号id
|
||||
* @param device 设备标识
|
||||
*/
|
||||
public static void logoutByLoginId(Object loginId, String device) {
|
||||
stpLogic.logoutByLoginId(loginId, device);
|
||||
}
|
||||
|
||||
|
||||
// 查询相关
|
||||
|
||||
/**
|
||||
* 获取当前会话是否已经登录
|
||||
* @return 是否已登录
|
||||
*/
|
||||
public static boolean isLogin() {
|
||||
return stpLogic.isLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检验当前会话是否已经登录,如未登录,则抛出异常
|
||||
*/
|
||||
public static void checkLogin() {
|
||||
stpLogic.checkLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话账号id, 如果未登录,则抛出异常
|
||||
* @return 账号id
|
||||
*/
|
||||
public static Object getLoginId() {
|
||||
return stpLogic.getLoginId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回默认值
|
||||
* @param <T> 返回类型
|
||||
* @param defaultValue 默认值
|
||||
* @return 登录id
|
||||
*/
|
||||
public static <T> T getLoginId(T defaultValue) {
|
||||
return stpLogic.getLoginId(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回null
|
||||
* @return 账号id
|
||||
*/
|
||||
public static Object getLoginIdDefaultNull() {
|
||||
return stpLogic.getLoginIdDefaultNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为String
|
||||
* @return 账号id
|
||||
*/
|
||||
public static String getLoginIdAsString() {
|
||||
return stpLogic.getLoginIdAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为int
|
||||
* @return 账号id
|
||||
*/
|
||||
public static int getLoginIdAsInt() {
|
||||
return stpLogic.getLoginIdAsInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为long
|
||||
* @return 账号id
|
||||
*/
|
||||
public static long getLoginIdAsLong() {
|
||||
return stpLogic.getLoginIdAsLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定token对应的登录id,如果未登录,则返回 null
|
||||
* @param tokenValue token
|
||||
* @return 登录id
|
||||
*/
|
||||
public static Object getLoginIdByToken(String tokenValue) {
|
||||
return stpLogic.getLoginIdByToken(tokenValue);
|
||||
}
|
||||
|
||||
|
||||
// =================== session相关 ===================
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session, 如果session尚未创建,isCreate=是否新建并返回
|
||||
* @param loginId 账号id
|
||||
* @param isCreate 是否新建
|
||||
* @return SaSession
|
||||
*/
|
||||
public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) {
|
||||
return stpLogic.getSessionByLoginId(loginId, isCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session,如果session尚未创建,则新建并返回
|
||||
* @param loginId 账号id
|
||||
* @return session会话
|
||||
*/
|
||||
public static SaSession getSessionByLoginId(Object loginId) {
|
||||
return stpLogic.getSessionByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的session, 如果session尚未创建,isCreate=是否新建并返回
|
||||
* @param isCreate 是否新建
|
||||
* @return 当前会话的session
|
||||
*/
|
||||
public static SaSession getSession(boolean isCreate) {
|
||||
return stpLogic.getSession(isCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的session,如果session尚未创建,则新建并返回
|
||||
* @return 当前会话的session
|
||||
*/
|
||||
public static SaSession getSession() {
|
||||
return stpLogic.getSession();
|
||||
}
|
||||
|
||||
|
||||
// =================== token专属session ===================
|
||||
|
||||
/**
|
||||
* 获取指定token的专属session,如果session尚未创建,则新建并返回
|
||||
* @param tokenValue token值
|
||||
* @return session会话
|
||||
*/
|
||||
public static SaSession getTokenSessionByToken(String tokenValue) {
|
||||
return stpLogic.getTokenSessionByToken(tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前token的专属-session,如果session尚未创建,则新建并返回
|
||||
* @return session会话
|
||||
*/
|
||||
public static SaSession getTokenSession() {
|
||||
return stpLogic.getTokenSession();
|
||||
}
|
||||
|
||||
|
||||
// =================== [临时过期] 验证相关 ===================
|
||||
|
||||
/**
|
||||
* 检查当前token 是否已经[临时过期],如果已经过期则抛出异常
|
||||
*/
|
||||
public static void checkActivityTimeout() {
|
||||
stpLogic.checkActivityTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 续签当前token:(将 [最后操作时间] 更新为当前时间戳)
|
||||
* <h1>请注意: 即时token已经 [临时过期] 也可续签成功,
|
||||
* 如果此场景下需要提示续签失败,可在此之前调用 checkActivityTimeout() 强制检查是否过期即可 </h1>
|
||||
*/
|
||||
public static void updateLastActivityToNow() {
|
||||
stpLogic.updateLastActivityToNow();
|
||||
}
|
||||
|
||||
|
||||
// =================== 过期时间相关 ===================
|
||||
|
||||
/**
|
||||
* 获取当前登录者的token剩余有效时间 (单位: 秒)
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public static long getTokenTimeout() {
|
||||
return stpLogic.getTokenTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录者的Session剩余有效时间 (单位: 秒)
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public static long getSessionTimeout() {
|
||||
return stpLogic.getSessionTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前token的专属Session剩余有效时间 (单位: 秒)
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public static long getTokenSessionTimeout() {
|
||||
return stpLogic.getTokenSessionTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前token[临时过期]剩余有效时间 (单位: 秒)
|
||||
* @return token[临时过期]剩余有效时间
|
||||
*/
|
||||
public static long getTokenActivityTimeout() {
|
||||
return stpLogic.getTokenActivityTimeout();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================== 角色验证操作 ===================
|
||||
|
||||
/**
|
||||
* 指定账号id是否含有角色标识
|
||||
* @param loginId 账号id
|
||||
* @param role 角色标识
|
||||
* @return 是否含有指定角色标识
|
||||
*/
|
||||
public static boolean hasRole(Object loginId, String role) {
|
||||
return stpLogic.hasRole(loginId, role);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号id是否含有指定角色标识
|
||||
* @param role 角色标识
|
||||
* @return 是否含有指定角色标识
|
||||
*/
|
||||
public static boolean hasRole(String role) {
|
||||
return stpLogic.hasRole(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定角色标识,没有就抛出异常
|
||||
* @param role 角色标识
|
||||
*/
|
||||
public static void checkRole(String role) {
|
||||
stpLogic.checkRole(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定角色标识, [指定多个,必须全都有]
|
||||
* @param roleArray 角色标识数组
|
||||
*/
|
||||
public static void checkRoleAnd(String... roleArray){
|
||||
stpLogic.checkRoleAnd(roleArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定角色标识, [指定多个,有一个就可以通过]
|
||||
* @param roleArray 角色标识数组
|
||||
*/
|
||||
public static void checkRoleOr(String... roleArray){
|
||||
stpLogic.checkRoleOr(roleArray);
|
||||
}
|
||||
|
||||
|
||||
// =================== 权限验证操作 ===================
|
||||
|
||||
/**
|
||||
* 指定账号id是否含有指定权限
|
||||
* @param loginId 账号id
|
||||
* @param permissionCode 权限码
|
||||
* @return 是否含有指定权限
|
||||
*/
|
||||
public static boolean hasPermission(Object loginId, String permissionCode) {
|
||||
return stpLogic.hasPermission(loginId, permissionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号id是否含有指定权限
|
||||
* @param permissionCode 权限码
|
||||
* @return 是否含有指定权限
|
||||
*/
|
||||
public static boolean hasPermission(String permissionCode) {
|
||||
return stpLogic.hasPermission(permissionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限, 没有就抛出异常
|
||||
* @param permissionCode 权限码
|
||||
*/
|
||||
public static void checkPermission(String permissionCode) {
|
||||
stpLogic.checkPermission(permissionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限, [指定多个,必须全都有]
|
||||
* @param permissionCodeArray 权限码数组
|
||||
*/
|
||||
public static void checkPermissionAnd(String... permissionCodeArray) {
|
||||
stpLogic.checkPermissionAnd(permissionCodeArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限, [指定多个,有一个就可以通过]
|
||||
* @param permissionCodeArray 权限码数组
|
||||
*/
|
||||
public static void checkPermissionOr(String... permissionCodeArray) {
|
||||
stpLogic.checkPermissionOr(permissionCodeArray);
|
||||
}
|
||||
|
||||
|
||||
// =================== id 反查token 相关操作 ===================
|
||||
|
||||
/**
|
||||
* 获取指定loginId的tokenValue
|
||||
* <p> 在配置为允许并发登录时,此方法只会返回队列的最后一个token,
|
||||
* 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId
|
||||
* @param loginId 账号id
|
||||
* @return token值
|
||||
*/
|
||||
public static String getTokenValueByLoginId(Object loginId) {
|
||||
return stpLogic.getTokenValueByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId指定设备端的tokenValue
|
||||
* <p> 在配置为允许并发登录时,此方法只会返回队列的最后一个token,
|
||||
* 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId
|
||||
* @param loginId 账号id
|
||||
* @param device 设备标识
|
||||
* @return token值
|
||||
*/
|
||||
public static String getTokenValueByLoginId(Object loginId, String device) {
|
||||
return stpLogic.getTokenValueByLoginId(loginId, device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的tokenValue集合
|
||||
* @param loginId 账号id
|
||||
* @return 此loginId的所有相关token
|
||||
*/
|
||||
public static List<String> getTokenValueListByLoginId(Object loginId) {
|
||||
return stpLogic.getTokenValueListByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId指定设备端的tokenValue集合
|
||||
* @param loginId 账号id
|
||||
* @param device 设备标识
|
||||
* @return 此loginId的所有相关token
|
||||
*/
|
||||
public static List<String> getTokenValueListByLoginId(Object loginId, String device) {
|
||||
return stpLogic.getTokenValueListByLoginId(loginId, device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前token的登录设备
|
||||
* @return 当前令牌的登录设备
|
||||
*/
|
||||
public static String getLoginDevice() {
|
||||
return stpLogic.getLoginDevice();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* 任务调度Util
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTaskUtil {
|
||||
|
||||
/**
|
||||
* 延时指定毫秒执行一个函数
|
||||
* @param fc 要执行的函数
|
||||
* @param delay 延时的毫秒数
|
||||
* @return timer任务对象
|
||||
*/
|
||||
public static Timer setTimeout(FunctionRunClass fc, int delay) {
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
fc.run();
|
||||
timer.cancel();
|
||||
}
|
||||
}, delay);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 延时delay毫秒,每隔period毫秒执行一个函数
|
||||
* @param fc 要执行的函数
|
||||
* @param delay 延时的毫秒数
|
||||
* @param period 每隔多少毫秒执行一次
|
||||
* @return timer任务对象
|
||||
*/
|
||||
public static Timer setInterval(FunctionRunClass fc, int delay, int period) {
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
fc.run();
|
||||
}
|
||||
}, delay, period);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装一个内部类,便于操作
|
||||
* @author kong
|
||||
*/
|
||||
public static interface FunctionRunClass{
|
||||
public void run();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
/**
|
||||
* 定义sa-token的所有常量
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenConsts {
|
||||
|
||||
/**
|
||||
* sa-token 版本号
|
||||
*/
|
||||
public static final String VERSION_NO = "v1.9.0";
|
||||
|
||||
/**
|
||||
* sa-token 开源地址
|
||||
*/
|
||||
public static final String GITHUB_URL = "https://github.com/click33/sa-token";
|
||||
|
||||
/**
|
||||
* 如果token为本次请求新创建的,则以此字符串为key存储在当前request中 JUST_CREATED_SAVE_KEY
|
||||
*/
|
||||
public static final String JUST_CREATED_SAVE_KEY = "JUST_CREATED_SAVE_KEY_";
|
||||
|
||||
/**
|
||||
* 如果本次请求已经验证过[无操作过期], 则以此值存储在当前request中 TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY
|
||||
*/
|
||||
public static final String TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY = "TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY_";
|
||||
|
||||
/**
|
||||
* 在登录时,默认使用的设备名称
|
||||
*/
|
||||
public static final String DEFAULT_LOGIN_DEVICE = "default-device";
|
||||
|
||||
// /**
|
||||
// * 在用一个字符串存储多个token时,所使用的分隔符
|
||||
// */
|
||||
// public static final String MULTIPLE_TOKEN_SEPARATOR = ",";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+12
-23
@@ -11,40 +11,21 @@ public class SaTokenInsideUtil {
|
||||
|
||||
|
||||
/**
|
||||
* sa-token 版本号
|
||||
*/
|
||||
public static final String VERSION_NO = "v1.7.0";
|
||||
|
||||
/**
|
||||
* sa-token 开源地址
|
||||
*/
|
||||
public static final String GITHUB_URL = "https://github.com/click33/sa-token";
|
||||
|
||||
/**
|
||||
* 打印 sa-token
|
||||
* 打印 sa-token 版本字符画
|
||||
*/
|
||||
public static void printSaToken() {
|
||||
String str =
|
||||
"____ ____ ___ ____ _ _ ____ _ _ \r\n" +
|
||||
"[__ |__| __ | | | |_/ |___ |\\ | \r\n" +
|
||||
"___] | | | |__| | \\_ |___ | \\| \r\n" +
|
||||
"sa-token:" + VERSION_NO + " \r\n" +
|
||||
"GitHub:" + GITHUB_URL; // + "\r\n";
|
||||
"sa-token:" + SaTokenConsts.VERSION_NO + " \r\n" +
|
||||
"GitHub:" + SaTokenConsts.GITHUB_URL; // + "\r\n";
|
||||
System.out.println(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果token为本次请求新创建的,则以此字符串为key存储在当前request中 JUST_CREATED_SAVE_KEY
|
||||
*/
|
||||
public static final String JUST_CREATED_SAVE_KEY = "JUST_CREATED_SAVE_KEY_";
|
||||
|
||||
/**
|
||||
* 如果本次请求已经验证过[无操作过期], 则以此值存储在当前request中 TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY
|
||||
*/
|
||||
public static final String TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY = "TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY_";
|
||||
|
||||
/**
|
||||
* 生成指定长度的随机字符串
|
||||
* 生成指定长度的随机字符串
|
||||
* @param length 字符串的长度
|
||||
* @return 一个随机字符串
|
||||
*/
|
||||
@@ -59,5 +40,13 @@ public class SaTokenInsideUtil {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 以当前时间戳和随机int数字拼接一个随机字符串
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String getMarking28() {
|
||||
return System.currentTimeMillis() + "" + new Random().nextInt(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
target/
|
||||
|
||||
node_modules/
|
||||
bin/
|
||||
.settings/
|
||||
unpackage/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
.factorypath
|
||||
|
||||
.idea/
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>sa-token-dao-redis-jackson</name>
|
||||
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||
<description>sa-token integrate redis (to jackson)</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- sa-token-spring-boot-starter -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
<!-- RedisTemplate 相关操作API -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<version>2.3.3.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
</project>
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package cn.dev33.satoken.dao;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* sa-token持久层的实现类, 基于redis (to jackson)
|
||||
*/
|
||||
@Component
|
||||
public class SaTokenDaoRedisJackson implements SaTokenDao {
|
||||
|
||||
/**
|
||||
* ObjectMapper对象 (以public作用于暴露出此对象,方便开发者二次更改配置)
|
||||
*/
|
||||
public ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* string专用
|
||||
*/
|
||||
@Autowired
|
||||
public StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* SaSession专用
|
||||
*/
|
||||
public RedisTemplate<String, SaSession> sessionRedisTemplate;
|
||||
@Autowired
|
||||
public void setSessionRedisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
// 指定相应的序列化方案
|
||||
StringRedisSerializer keySerializer = new StringRedisSerializer();
|
||||
GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();
|
||||
// 通过反射获取Mapper对象, 配置[忽略未知字段], 增强兼容性
|
||||
try {
|
||||
Field field = GenericJackson2JsonRedisSerializer.class.getDeclaredField("mapper");
|
||||
field.setAccessible(true);
|
||||
ObjectMapper objectMapper = (ObjectMapper) field.get(valueSerializer);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
this.objectMapper = objectMapper;
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
}
|
||||
// 构建RedisTemplate
|
||||
RedisTemplate<String, SaSession> template = new RedisTemplate<String, SaSession>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
template.setKeySerializer(keySerializer);
|
||||
template.setHashKeySerializer(keySerializer);
|
||||
template.setValueSerializer(valueSerializer);
|
||||
template.setHashValueSerializer(valueSerializer);
|
||||
template.afterPropertiesSet();
|
||||
if(this.sessionRedisTemplate == null) {
|
||||
this.sessionRedisTemplate = template;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据key获取value,如果没有,则返回空
|
||||
*/
|
||||
@Override
|
||||
public String getValue(String key) {
|
||||
return stringRedisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入指定key-value键值对,并设定过期时间(单位:秒)
|
||||
*/
|
||||
@Override
|
||||
public void setValue(String key, String value, long timeout) {
|
||||
// 判断是否为永不过期
|
||||
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 = getTimeout(key);
|
||||
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键
|
||||
return;
|
||||
}
|
||||
this.setValue(key, value, expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个指定的key
|
||||
*/
|
||||
@Override
|
||||
public void deleteKey(String key) {
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据key获取value,如果没有,则返回空
|
||||
*/
|
||||
@Override
|
||||
public long getTimeout(String key) {
|
||||
return stringRedisTemplate.getExpire(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改指定key的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
@Override
|
||||
public void updateTimeout(String key, long timeout) {
|
||||
stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 根据指定key的Session,如果没有,则返回空
|
||||
*/
|
||||
@Override
|
||||
public SaSession getSession(String sessionId) {
|
||||
return sessionRedisTemplate.opsForValue().get(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定Session持久化
|
||||
*/
|
||||
@Override
|
||||
public void saveSession(SaSession session, long timeout) {
|
||||
// 判断是否为永不过期
|
||||
if(timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||
sessionRedisTemplate.opsForValue().set(session.getId(), session);
|
||||
} else {
|
||||
sessionRedisTemplate.opsForValue().set(session.getId(), session, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指定session
|
||||
*/
|
||||
@Override
|
||||
public void updateSession(SaSession session) {
|
||||
long expire = getSessionTimeout(session.getId());
|
||||
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键
|
||||
return;
|
||||
}
|
||||
this.saveSession(session, expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个指定的session
|
||||
*/
|
||||
@Override
|
||||
public void deleteSession(String sessionId) {
|
||||
sessionRedisTemplate.delete(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定SaSession的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
@Override
|
||||
public long getSessionTimeout(String sessionId) {
|
||||
return sessionRedisTemplate.getExpire(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改指定SaSession的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
@Override
|
||||
public void updateSessionTimeout(String sessionId, long timeout) {
|
||||
sessionRedisTemplate.expire(sessionId, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.dao.SaTokenDaoRedisJackson
|
||||
@@ -0,0 +1,12 @@
|
||||
target/
|
||||
|
||||
node_modules/
|
||||
bin/
|
||||
.settings/
|
||||
unpackage/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
.factorypath
|
||||
|
||||
.idea/
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>sa-token-dao-redis</name>
|
||||
<artifactId>sa-token-dao-redis</artifactId>
|
||||
<description>sa-token integrate redis</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- sa-token-spring-boot-starter -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
<!-- RedisTemplate 相关操作API -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<version>2.3.3.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,166 @@
|
||||
package cn.dev33.satoken.dao;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
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.session.SaSession;
|
||||
|
||||
/**
|
||||
* sa-token持久层的实现类, 基于redis
|
||||
*/
|
||||
@Component
|
||||
public class SaTokenDaoRedis implements SaTokenDao {
|
||||
|
||||
/**
|
||||
* string专用
|
||||
*/
|
||||
@Autowired
|
||||
public StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* SaSession专用
|
||||
*/
|
||||
public RedisTemplate<String, SaSession> sessionRedisTemplate;
|
||||
@Autowired
|
||||
public void setSessionRedisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
// 指定相应的序列化方案
|
||||
StringRedisSerializer keySerializer = new StringRedisSerializer();
|
||||
JdkSerializationRedisSerializer valueSerializer = new JdkSerializationRedisSerializer();
|
||||
// 构建RedisTemplate
|
||||
RedisTemplate<String, SaSession> template = new RedisTemplate<String, SaSession>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
template.setKeySerializer(keySerializer);
|
||||
template.setHashKeySerializer(keySerializer);
|
||||
template.setValueSerializer(valueSerializer);
|
||||
template.setHashValueSerializer(valueSerializer);
|
||||
template.afterPropertiesSet();
|
||||
if(this.sessionRedisTemplate == null) {
|
||||
this.sessionRedisTemplate = template;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据key获取value,如果没有,则返回空
|
||||
*/
|
||||
@Override
|
||||
public String getValue(String key) {
|
||||
return stringRedisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入指定key-value键值对,并设定过期时间(单位:秒)
|
||||
*/
|
||||
@Override
|
||||
public void setValue(String key, String value, long timeout) {
|
||||
// 判断是否为永不过期
|
||||
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 = getTimeout(key);
|
||||
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键
|
||||
return;
|
||||
}
|
||||
this.setValue(key, value, expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个指定的key
|
||||
*/
|
||||
@Override
|
||||
public void deleteKey(String key) {
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据key获取value,如果没有,则返回空
|
||||
*/
|
||||
@Override
|
||||
public long getTimeout(String key) {
|
||||
return stringRedisTemplate.getExpire(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改指定key的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
@Override
|
||||
public void updateTimeout(String key, long timeout) {
|
||||
stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 根据指定key的Session,如果没有,则返回空
|
||||
*/
|
||||
@Override
|
||||
public SaSession getSession(String sessionId) {
|
||||
return sessionRedisTemplate.opsForValue().get(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定Session持久化
|
||||
*/
|
||||
@Override
|
||||
public void saveSession(SaSession session, long timeout) {
|
||||
// 判断是否为永不过期
|
||||
if(timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||
sessionRedisTemplate.opsForValue().set(session.getId(), session);
|
||||
} else {
|
||||
sessionRedisTemplate.opsForValue().set(session.getId(), session, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指定session
|
||||
*/
|
||||
@Override
|
||||
public void updateSession(SaSession session) {
|
||||
long expire = getSessionTimeout(session.getId());
|
||||
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键
|
||||
return;
|
||||
}
|
||||
this.saveSession(session, expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个指定的session
|
||||
*/
|
||||
@Override
|
||||
public void deleteSession(String sessionId) {
|
||||
sessionRedisTemplate.delete(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定SaSession的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
@Override
|
||||
public long getSessionTimeout(String sessionId) {
|
||||
return sessionRedisTemplate.getExpire(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改指定SaSession的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
@Override
|
||||
public void updateSessionTimeout(String sessionId, long timeout) {
|
||||
sessionRedisTemplate.expire(sessionId, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.dao.SaTokenDaoRedis
|
||||
@@ -1,52 +0,0 @@
|
||||
<factorypath>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-web/2.0.0.RELEASE/spring-boot-starter-web-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter/2.0.0.RELEASE/spring-boot-starter-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot/2.0.0.RELEASE/spring-boot-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-autoconfigure/2.0.0.RELEASE/spring-boot-autoconfigure-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-logging/2.0.0.RELEASE/spring-boot-starter-logging-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-to-slf4j/2.10.0/log4j-to-slf4j-2.10.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-api/2.10.0/log4j-api-2.10.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-core/5.0.4.RELEASE/spring-core-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-jcl/5.0.4.RELEASE/spring-jcl-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/yaml/snakeyaml/1.19/snakeyaml-1.19.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-json/2.0.0.RELEASE/spring-boot-starter-json-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-databind/2.9.4/jackson-databind-2.9.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-core/2.9.4/jackson-core-2.9.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.4/jackson-datatype-jdk8-2.9.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.4/jackson-datatype-jsr310-2.9.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.4/jackson-module-parameter-names-2.9.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-tomcat/2.0.0.RELEASE/spring-boot-starter-tomcat-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-core/8.5.28/tomcat-embed-core-8.5.28.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-el/8.5.28/tomcat-embed-el-8.5.28.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-websocket/8.5.28/tomcat-embed-websocket-8.5.28.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/hibernate/validator/hibernate-validator/6.0.7.Final/hibernate-validator-6.0.7.Final.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/classmate/1.3.4/classmate-1.3.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-web/5.0.4.RELEASE/spring-web-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-beans/5.0.4.RELEASE/spring-beans-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-webmvc/5.0.4.RELEASE/spring-webmvc-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context/5.0.4.RELEASE/spring-context-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-expression/5.0.4.RELEASE/spring-expression-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-aop/2.0.0.RELEASE/spring-boot-starter-aop-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-aop/5.0.4.RELEASE/spring-aop-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-redis/1.4.7.RELEASE/spring-boot-starter-redis-1.4.7.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-redis/2.0.5.RELEASE/spring-data-redis-2.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-keyvalue/2.0.5.RELEASE/spring-data-keyvalue-2.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-commons/2.0.5.RELEASE/spring-data-commons-2.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-tx/5.0.4.RELEASE/spring-tx-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-oxm/5.0.4.RELEASE/spring-oxm-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context-support/5.0.4.RELEASE/spring-context-support-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/redis/clients/jedis/2.9.0/jedis-2.9.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-pool2/2.5.0/commons-pool2-2.5.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-configuration-processor/2.0.0.RELEASE/spring-boot-configuration-processor-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="PLUGIN" id="net.harawata.mybatipse" enabled="false" runInBatchMode="false"/>
|
||||
</factorypath>
|
||||
@@ -7,4 +7,6 @@ unpackage/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
.idea/
|
||||
.idea/
|
||||
|
||||
.factorypath
|
||||
@@ -29,15 +29,28 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot整合redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-redis</artifactId>
|
||||
<version>RELEASE</version>
|
||||
</dependency>
|
||||
<!-- sa-token整合redis (使用jdk默认序列化方式) -->
|
||||
<!-- <dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency> -->
|
||||
|
||||
<!-- sa-token整合redis (使用jackson序列化方式) -->
|
||||
<!-- <dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency> -->
|
||||
|
||||
<!-- 提供redis连接池 -->
|
||||
<!-- <dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency> -->
|
||||
|
||||
<!-- @ConfigurationProperties -->
|
||||
<dependency>
|
||||
|
||||
@@ -7,7 +7,7 @@ import cn.dev33.satoken.SaTokenManager;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SaTokenDemoApplication {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args);
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaTokenManager.getConfig());
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.action.SaTokenActionDefaultImpl;
|
||||
|
||||
/**
|
||||
* 继承sa-token行为Bean默认实现, 重写部分逻辑
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class MySaTokenAction extends SaTokenActionDefaultImpl {
|
||||
|
||||
// 重写token生成策略
|
||||
// @Override
|
||||
// public String createToken(Object loginId, String loginKey) {
|
||||
// return SaTokenInsideUtil.getRandomString(60);
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -20,12 +20,10 @@ public class MySaTokenConfig implements WebMvcConfigurer {
|
||||
SaTokenConfig config = new SaTokenConfig();
|
||||
config.setTokenName("satoken"); // token名称 (同时也是cookie名称)
|
||||
config.setTimeout(30 * 24 * 60 * 60); // token有效期,单位s 默认30天
|
||||
config.setIsShare(true); // 在多人登录同一账号时,是否共享会话 (为true时共用一个,为false时新登录挤掉旧登录)
|
||||
config.setIsReadBody(true); // 是否尝试从请求体里读取token
|
||||
config.setIsReadHead(true); // 是否尝试从header里读取token
|
||||
config.setIsReadCookie(true); // 是否尝试从cookie里读取token
|
||||
config.setActivityTimeout(-1); // token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
config.setAllowConcurrentLogin(true); // 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
config.setIsShare(true); // 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
config.setTokenStyle("uuid"); // token风格
|
||||
config.setIsV(true); // 是否在初始化配置时打印版本字符画
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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 cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* sa-token持久层的实现类 , 基于redis
|
||||
*/
|
||||
//@Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token与redis的集成
|
||||
public class SaTokenDaoRedis implements SaTokenDao {
|
||||
|
||||
|
||||
// string专用
|
||||
@Autowired
|
||||
StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
// SaSession专用
|
||||
RedisTemplate<String, SaSession> redisTemplate;
|
||||
@Autowired
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void setRedisTemplate(RedisTemplate redisTemplate) {
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
|
||||
// 根据key获取value ,如果没有,则返回空
|
||||
@Override
|
||||
public String getValue(String key) {
|
||||
return stringRedisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
// 写入指定key-value键值对,并设定过期时间(单位:秒)
|
||||
@Override
|
||||
public void setValue(String key, String value, long timeout) {
|
||||
// 判断是否为永不过期
|
||||
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 = getTimeout(key);
|
||||
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键
|
||||
return;
|
||||
}
|
||||
this.setValue(key, value, expire);
|
||||
}
|
||||
|
||||
// 删除一个指定的key
|
||||
@Override
|
||||
public void deleteKey(String key) {
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
|
||||
// 获取指定key的剩余存活时间 (单位: 秒)
|
||||
@Override
|
||||
public long getTimeout(String key) {
|
||||
return stringRedisTemplate.getExpire(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 根据指定key的session,如果没有,则返回空
|
||||
@Override
|
||||
public SaSession getSession(String sessionId) {
|
||||
return redisTemplate.opsForValue().get(sessionId);
|
||||
}
|
||||
|
||||
// 将指定session持久化
|
||||
@Override
|
||||
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 updateSession(SaSession session) {
|
||||
long expire = getSessionTimeout(session.getId());
|
||||
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键
|
||||
return;
|
||||
}
|
||||
this.saveSession(session, expire);
|
||||
}
|
||||
|
||||
// 删除一个指定的session
|
||||
@Override
|
||||
public void deleteSession(String sessionId) {
|
||||
redisTemplate.delete(sessionId);
|
||||
}
|
||||
|
||||
// 获取指定SaSession的剩余存活时间 (单位: 秒)
|
||||
@Override
|
||||
public long getSessionTimeout(String sessionId) {
|
||||
return redisTemplate.getExpire(sessionId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -8,15 +8,17 @@ import org.springframework.stereotype.Component;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
|
||||
/**
|
||||
* 自定义权限验证接口扩展
|
||||
* 自定义权限验证接口扩展
|
||||
*/
|
||||
@Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token的自定义权限验证扩展
|
||||
public class StpInterfaceImpl implements StpInterface {
|
||||
|
||||
// 返回一个账号所拥有的权限码集合
|
||||
/**
|
||||
* 返回一个账号所拥有的权限码集合
|
||||
*/
|
||||
@Override
|
||||
public List<Object> getPermissionCodeList(Object login_id, String login_key) {
|
||||
List<Object> list = new ArrayList<Object>(); // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
|
||||
public List<String> getPermissionList(Object login_id, String login_key) {
|
||||
List<String> list = new ArrayList<String>(); // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
|
||||
list.add("101");
|
||||
list.add("user-add");
|
||||
list.add("user-delete");
|
||||
@@ -26,4 +28,15 @@ public class StpInterfaceImpl implements StpInterface {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回一个账号所拥有的角色标识集合
|
||||
*/
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginKey) {
|
||||
List<String> list = new ArrayList<String>(); // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色
|
||||
list.add("admin");
|
||||
list.add("super-admin");
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,285 +0,0 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
|
||||
/**
|
||||
* 一个默认的实现
|
||||
* @author kong
|
||||
*/
|
||||
public class StpUserUtil {
|
||||
|
||||
/**
|
||||
* 底层的 StpLogic 对象
|
||||
*/
|
||||
public static StpLogic stpLogic = new StpLogic("user");
|
||||
|
||||
|
||||
// =================== 获取token 相关 ===================
|
||||
|
||||
/**
|
||||
* 返回token名称
|
||||
* @return 此StpLogic的token名称
|
||||
*/
|
||||
public static String getTokenName() {
|
||||
return stpLogic.getTokenName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前tokenValue
|
||||
* @return 当前tokenValue
|
||||
*/
|
||||
public static String getTokenValue() {
|
||||
return stpLogic.getTokenValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定id的tokenValue
|
||||
* @param loginId .
|
||||
* @return
|
||||
*/
|
||||
public static String getTokenValueByLoginId(Object loginId) {
|
||||
return stpLogic.getTokenValueByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
*/
|
||||
public static String getLoginKey(){
|
||||
return stpLogic.getLoginKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的token信息
|
||||
* @return token信息
|
||||
*/
|
||||
public static SaTokenInfo getTokenInfo() {
|
||||
return stpLogic.getTokenInfo();
|
||||
}
|
||||
|
||||
// =================== 登录相关操作 ===================
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id
|
||||
* @param loginId 登录id ,建议的类型:(long | int | String)
|
||||
*/
|
||||
public static void setLoginId(Object loginId) {
|
||||
stpLogic.setLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话注销登录
|
||||
*/
|
||||
public static void logout() {
|
||||
stpLogic.logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId的会话注销登录(清退下线)
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public static void logoutByLoginId(Object loginId) {
|
||||
stpLogic.logoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId的会话注销登录(踢人下线)
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public static void kickoutByLoginId(Object loginId) {
|
||||
stpLogic.kickoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
// 查询相关
|
||||
|
||||
/**
|
||||
* 获取当前会话是否已经登录
|
||||
* @return 是否已登录
|
||||
*/
|
||||
public static boolean isLogin() {
|
||||
return stpLogic.isLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检验当前会话是否已经登录,如未登录,则抛出异常
|
||||
*/
|
||||
public static void checkLogin() {
|
||||
getLoginId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则抛出异常
|
||||
* @return .
|
||||
*/
|
||||
public static Object getLoginId() {
|
||||
return stpLogic.getLoginId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回默认值
|
||||
* @param defaultValue .
|
||||
* @return .
|
||||
*/
|
||||
public static <T> T getLoginId(T defaultValue) {
|
||||
return stpLogic.getLoginId(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回null
|
||||
* @return
|
||||
*/
|
||||
public static Object getLoginIdDefaultNull() {
|
||||
return stpLogic.getLoginIdDefaultNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为String
|
||||
* @return
|
||||
*/
|
||||
public static String getLoginIdAsString() {
|
||||
return stpLogic.getLoginIdAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为int
|
||||
* @return
|
||||
*/
|
||||
public static int getLoginIdAsInt() {
|
||||
return stpLogic.getLoginIdAsInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为long
|
||||
* @return
|
||||
*/
|
||||
public static long getLoginIdAsLong() {
|
||||
return stpLogic.getLoginIdAsLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定token对应的登录id,如果未登录,则返回 null
|
||||
* @return .
|
||||
*/
|
||||
public static Object getLoginIdByToken(String tokenValue) {
|
||||
return stpLogic.getLoginIdByToken(tokenValue);
|
||||
}
|
||||
|
||||
|
||||
// =================== session相关 ===================
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session, 如果没有,isCreate=是否新建并返回
|
||||
* @param loginId 登录id
|
||||
* @param isCreate 是否新建
|
||||
* @return SaSession
|
||||
*/
|
||||
public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) {
|
||||
return stpLogic.getSessionByLoginId(loginId, isCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session
|
||||
* @param loginId .
|
||||
* @return .
|
||||
*/
|
||||
public static SaSession getSessionByLoginId(Object loginId) {
|
||||
return stpLogic.getSessionByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的session
|
||||
* @return
|
||||
*/
|
||||
public static SaSession getSession() {
|
||||
return stpLogic.getSession();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================== 过期时间相关 ===================
|
||||
|
||||
/**
|
||||
* 获取当前登录者的token剩余有效时间 (单位: 秒)
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return stpLogic.getTokenTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的token剩余有效时间 (单位: 秒)
|
||||
* @param loginId 指定loginId
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getTimeoutByLoginId(Object loginId) {
|
||||
return stpLogic.getTokenTimeoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录者的Session剩余有效时间 (单位: 秒)
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getSessionTimeout() {
|
||||
return stpLogic.getSessionTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的Session剩余有效时间 (单位: 秒)
|
||||
* @param loginId 指定loginId
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getSessionTimeoutByLoginId(Object loginId) {
|
||||
return stpLogic.getSessionTimeoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================== 权限验证操作 ===================
|
||||
|
||||
/**
|
||||
* 指定loginId是否含有指定权限
|
||||
* @param loginId .
|
||||
* @param pcode .
|
||||
* @return .
|
||||
*/
|
||||
public static boolean hasPermission(Object loginId, Object pcode) {
|
||||
return stpLogic.hasPermission(loginId, pcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话是否含有指定权限
|
||||
* @param pcode .
|
||||
* @return .
|
||||
*/
|
||||
public static boolean hasPermission(Object pcode) {
|
||||
return stpLogic.hasPermission(pcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 , 没有就抛出异常
|
||||
* @param pcode .
|
||||
*/
|
||||
public static void checkPermission(Object pcode) {
|
||||
stpLogic.checkPermission(pcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 , 【指定多个,必须全都有】
|
||||
* @param pcodeArray .
|
||||
*/
|
||||
public static void checkPermissionAnd(Object... pcodeArray) {
|
||||
stpLogic.checkPermissionAnd(pcodeArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 , 【指定多个,有一个就可以了】
|
||||
* @param pcodeArray .
|
||||
*/
|
||||
public static void checkPermissionOr(Object... pcodeArray) {
|
||||
stpLogic.checkPermissionOr(pcodeArray);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
|
||||
/**
|
||||
* 全局异常处理
|
||||
@@ -40,6 +41,9 @@ public class GlobalException {
|
||||
if (e instanceof NotLoginException) { // 如果是未登录异常
|
||||
NotLoginException ee = (NotLoginException) e;
|
||||
aj = AjaxJson.getNotLogin().setMsg(ee.getMessage());
|
||||
} else if(e instanceof NotRoleException) { // 如果是角色异常
|
||||
NotRoleException ee = (NotRoleException) e;
|
||||
aj = AjaxJson.getNotJur("无此角色:" + ee.getRole());
|
||||
} else if(e instanceof NotPermissionException) { // 如果是权限异常
|
||||
NotPermissionException ee = (NotPermissionException) e;
|
||||
aj = AjaxJson.getNotJur("无此权限:" + ee.getCode());
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
package com.pj.test;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.dev33.satoken.session.SaSessionCustomUtil;
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
@@ -27,31 +34,54 @@ public class TestController {
|
||||
System.out.println("当前会话的token:" + StpUtil.getTokenValue());
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前登录账号:" + StpUtil.getLoginIdDefaultNull());
|
||||
|
||||
StpUtil.setLoginId(id); // 在当前会话登录此账号
|
||||
System.out.println("登录成功");
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前登录账号:" + StpUtil.getLoginId());
|
||||
System.out.println("当前登录账号:" + StpUtil.getLoginIdAsInt()); // 获取登录id并转为int
|
||||
|
||||
// StpUtil.logout();
|
||||
// System.out.println("注销登录");
|
||||
// System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
// System.out.println("当前登录账号:" + StpUtil.getLoginIdDefaultNull());
|
||||
// StpUtil.setLoginId(id); // 在当前会话登录此账号
|
||||
// System.out.println("根据token找登录id:" + StpUtil.getLoginIdByToken(StpUtil.getTokenValue()));
|
||||
|
||||
System.out.println("当前token信息:" + StpUtil.getTokenInfo()); // 获取登录id并转为int
|
||||
System.out.println("当前登录账号:" + StpUtil.getLoginIdDefaultNull());
|
||||
// System.out.println("当前登录账号并转为int:" + StpUtil.getLoginIdAsInt());
|
||||
System.out.println("当前登录设备:" + StpUtil.getLoginDevice());
|
||||
// System.out.println("当前token信息:" + StpUtil.getTokenInfo());
|
||||
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试权限接口, 浏览器访问: http://localhost:8081/test/jur
|
||||
@RequestMapping("jur")
|
||||
public AjaxJson jur() {
|
||||
// 测试退出登录 , 浏览器访问: http://localhost:8081/test/logout
|
||||
@RequestMapping("logout")
|
||||
public AjaxJson logout() {
|
||||
StpUtil.logout();
|
||||
// StpUtil.logoutByLoginId(10001);
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试角色接口, 浏览器访问: http://localhost:8081/test/testRole
|
||||
@RequestMapping("testRole")
|
||||
public AjaxJson testRole() {
|
||||
System.out.println("======================= 进入方法,测试角色接口 ========================= ");
|
||||
|
||||
System.out.println("是否具有角色标识 user " + StpUtil.hasRole("user"));
|
||||
System.out.println("是否具有角色标识 admin " + StpUtil.hasRole("admin"));
|
||||
|
||||
System.out.println("没有admin权限就抛出异常");
|
||||
StpUtil.checkRole("admin");
|
||||
|
||||
System.out.println("在【admin、user】中只要拥有一个就不会抛出异常");
|
||||
StpUtil.checkRoleOr("admin", "user");
|
||||
|
||||
System.out.println("在【admin、user】中必须全部拥有才不会抛出异常");
|
||||
StpUtil.checkRoleAnd("admin", "user");
|
||||
|
||||
System.out.println("角色测试通过");
|
||||
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试权限接口, 浏览器访问: http://localhost:8081/test/testJur
|
||||
@RequestMapping("testJur")
|
||||
public AjaxJson testJur() {
|
||||
System.out.println("======================= 进入方法,测试权限接口 ========================= ");
|
||||
|
||||
System.out.println("是否具有权限101" + StpUtil.hasPermission(101));
|
||||
System.out.println("是否具有权限101" + StpUtil.hasPermission("101"));
|
||||
System.out.println("是否具有权限user-add" + StpUtil.hasPermission("user-add"));
|
||||
System.out.println("是否具有权限article-get" + StpUtil.hasPermission("article-get"));
|
||||
|
||||
@@ -71,14 +101,15 @@ public class TestController {
|
||||
|
||||
// 测试会话session接口, 浏览器访问: http://localhost:8081/test/session
|
||||
@RequestMapping("session")
|
||||
public AjaxJson session() {
|
||||
public AjaxJson session() throws JsonProcessingException {
|
||||
System.out.println("======================= 进入方法,测试会话session接口 ========================= ");
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前登录账号session的id" + StpUtil.getSession().getId());
|
||||
System.out.println("当前登录账号session的id" + StpUtil.getSession().getId());
|
||||
System.out.println("测试取值name:" + StpUtil.getSession().getAttribute("name"));
|
||||
StpUtil.getSession().setAttribute("name", "张三"); // 写入一个值
|
||||
StpUtil.getSession().setAttribute("name", new Date()); // 写入一个值
|
||||
System.out.println("测试取值name:" + StpUtil.getSession().getAttribute("name"));
|
||||
System.out.println( new ObjectMapper().writeValueAsString(StpUtil.getSession()));
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
@@ -95,6 +126,22 @@ public class TestController {
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// ----------
|
||||
// 测试token专属session, 浏览器访问: http://localhost:8081/test/getTokenSession
|
||||
@RequestMapping("getTokenSession")
|
||||
public AjaxJson getTokenSession() {
|
||||
System.out.println("======================= 进入方法,测试会话session接口 ========================= ");
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前token专属session: " + StpUtil.getTokenSession().getId());
|
||||
|
||||
System.out.println("测试取值name:" + StpUtil.getTokenSession().getAttribute("name"));
|
||||
StpUtil.getTokenSession().setAttribute("name", "张三"); // 写入一个值
|
||||
System.out.println("测试取值name:" + StpUtil.getTokenSession().getAttribute("name"));
|
||||
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
|
||||
// 打印当前token信息, 浏览器访问: http://localhost:8081/test/tokenInfo
|
||||
@RequestMapping("tokenInfo")
|
||||
public AjaxJson tokenInfo() {
|
||||
@@ -104,27 +151,26 @@ public class TestController {
|
||||
return AjaxJson.getSuccessData(tokenInfo);
|
||||
}
|
||||
|
||||
|
||||
// 测试注解式鉴权, 浏览器访问: http://localhost:8081/test/atCheck
|
||||
@SaCheckLogin // 注解式鉴权:当前会话必须登录才能通过
|
||||
@SaCheckRole("super-admin") // 注解式鉴权:当前会话必须具有指定角色标识才能通过
|
||||
@SaCheckPermission("user-add") // 注解式鉴权:当前会话必须具有指定权限才能通过
|
||||
@RequestMapping("atCheck")
|
||||
public AjaxJson atCheck() {
|
||||
System.out.println("======================= 进入方法,测试注解鉴权接口 ========================= ");
|
||||
System.out.println("只有通过注解鉴权,才能进入此方法");
|
||||
StpUtil.checkActivityTimeout();
|
||||
StpUtil.updateLastActivityToNow();
|
||||
// StpUtil.checkActivityTimeout();
|
||||
// StpUtil.updateLastActivityToNow();
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试注解式鉴权, 浏览器访问: http://localhost:8081/test/atLogin
|
||||
@SaCheckLogin // 注解式鉴权:当前会话必须登录才能通过
|
||||
@RequestMapping("atLogin")
|
||||
public AjaxJson atLogin() {
|
||||
// 测试注解式鉴权, 浏览器访问: http://localhost:8081/test/atJurOr
|
||||
@RequestMapping("atJurOr")
|
||||
@SaCheckPermission(value = {"user-add", "user-all", "user-delete"}, mode = SaMode.OR) // 注解式鉴权:只要具有其中一个权限即可通过校验
|
||||
public AjaxJson atJurOr() {
|
||||
return AjaxJson.getSuccessData("用户信息");
|
||||
}
|
||||
|
||||
|
||||
// [活动时间] 续签: http://localhost:8081/test/rene
|
||||
@RequestMapping("rene")
|
||||
public AjaxJson rene() {
|
||||
@@ -133,39 +179,34 @@ public class TestController {
|
||||
return AjaxJson.getSuccess("续签成功");
|
||||
}
|
||||
|
||||
|
||||
// 测试踢人下线 浏览器访问: http://localhost:8081/test/kickOut
|
||||
@RequestMapping("kickOut")
|
||||
public AjaxJson kickOut() {
|
||||
// 先登录上
|
||||
StpUtil.setLoginId(10001);
|
||||
// 清退下线
|
||||
// StpUtil.logoutByLoginId(10001);
|
||||
// 踢下线
|
||||
StpUtil.kickoutByLoginId(10001);
|
||||
StpUtil.logoutByLoginId(10001);
|
||||
// 再尝试获取
|
||||
StpUtil.getLoginId();
|
||||
// 返回
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
|
||||
// 测试 浏览器访问: http://localhost:8081/test/test
|
||||
@RequestMapping("test")
|
||||
public AjaxJson test() {
|
||||
StpUtil.setLoginId(10001);
|
||||
// StpUtil.getSession();
|
||||
StpUtil.logout();
|
||||
|
||||
// System.out.println(StpUtil.getSession().getId());
|
||||
// System.out.println(StpUserUtil.getSession().getId());
|
||||
// StpUtil.getSessionByLoginId(10001).setAttribute("name", "123");
|
||||
// System.out.println(StpUtil.getSessionByLoginId(10001).getAttribute("name"));
|
||||
|
||||
// StpUtil.getTokenSession().logout();
|
||||
StpUtil.logoutByLoginId(10001);
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 测试登录接口, 按照设备登录, 浏览器访问: http://localhost:8081/test/login2
|
||||
@RequestMapping("login2")
|
||||
public AjaxJson login2(@RequestParam(defaultValue="10001") String id, @RequestParam(defaultValue="PC") String device) {
|
||||
StpUtil.setLoginId(id, device);
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,20 +9,14 @@ spring:
|
||||
token-name: satoken
|
||||
# token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: 2592000
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒, 默认-1 代表不限制 (例如可以设置为1800代表30分钟内无操作就过期)
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
activity-timeout: -1
|
||||
# 在多人登录同一账号时,是否共享会话 (为true时共用一个,为false时新登录挤掉旧登录)
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
allow-concurrent-login: true
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
is-share: true
|
||||
# 是否尝试从请求体里读取token
|
||||
is-read-body: true
|
||||
# 是否尝试从header里读取token
|
||||
is-read-head: true
|
||||
# 是否尝试从cookie里读取token
|
||||
is-read-cookie: true
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否在初始化配置时打印版本字符画
|
||||
is-v: true
|
||||
|
||||
|
||||
# redis配置
|
||||
|
||||
+59
-37
@@ -1,11 +1,11 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://gitee.com/sz6/sa-token/raw/master/sa-token-doc/doc/logo.png" width="150" height="150" style="margin-bottom: 10px;">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.7.0</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.9.0</h1>
|
||||
<h4 align="center">一个JavaWeb轻量级权限认证框架,功能全面,上手简单</h4>
|
||||
<h4 align="center">
|
||||
<a href="https://gitee.com/sz6/sa-token/stargazers"><img src="https://gitee.com/sz6/sa-token/badge/star.svg"></a>
|
||||
<a href="https://github.com/click33/sa-token"><img src="https://img.shields.io/badge/sa--token-v1.7.0-2B9939"></a>
|
||||
<a href="https://github.com/click33/sa-token"><img src="https://img.shields.io/badge/sa--token-v1.9.0-2B9939"></a>
|
||||
<a href="https://github.com/click33/sa-token/stargazers"><img src="https://img.shields.io/github/stars/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/watchers"><img src="https://img.shields.io/github/watchers/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/network/members"><img src="https://img.shields.io/github/forks/click33/sa-token"></a>
|
||||
@@ -16,54 +16,76 @@
|
||||
---
|
||||
|
||||
|
||||
## 😘 在线资料
|
||||
- ##### [官网首页:http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
|
||||
- ##### [在线文档:http://sa-token.dev33.cn/doc/index.html](http://sa-token.dev33.cn/doc/index.html)
|
||||
- ##### [需求提交:我们深知一个优秀的项目需要海纳百川,点我在线提交需求](http://sa-app.dev33.cn/wall.html?name=sa-token)
|
||||
- ##### [开源不易,求鼓励,点个star吧](https://github.com/click33/sa-token)
|
||||
## 在线资料
|
||||
|
||||
- [官网首页:http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
|
||||
|
||||
- [在线文档:http://sa-token.dev33.cn/doc/index.html](http://sa-token.dev33.cn/doc/index.html)
|
||||
|
||||
- [需求提交:我们深知一个优秀的项目需要海纳百川,点我在线提交需求](http://sa-app.dev33.cn/wall.html?name=sa-token)
|
||||
|
||||
- [开源不易,求鼓励,点个star吧](https://github.com/click33/sa-token)
|
||||
|
||||
|
||||
## ⭐ sa-token是什么?
|
||||
- **sa-token是一个JavaWeb轻量级权限认证框架,其API调用非常简单,有多简单呢?以登录验证为例,你只需要:**
|
||||
## sa-token是什么?
|
||||
sa-token是一个JavaWeb轻量级权限认证框架,其API调用非常简单,有多简单呢?以登录验证为例,你只需要:
|
||||
|
||||
``` java
|
||||
// 在登录时写入当前会话的账号id
|
||||
StpUtil.setLoginId(10001);
|
||||
StpUtil.setLoginId(10001);
|
||||
|
||||
// 然后在任意需要校验登录处调用以下API --- 如果当前会话未登录,这句代码会抛出 `NotLoginException`异常
|
||||
StpUtil.checkLogin();
|
||||
```
|
||||
|
||||
|
||||
- **然后在任意需要验证登录权限的地方:**
|
||||
``` java
|
||||
// 检测是否登录 --- 如果当前会话未登录,下面这句代码会抛出 `NotLoginException`异常
|
||||
StpUtil.checkLogin();
|
||||
```
|
||||
没有复杂的封装!不要任何的配置!只需这两行简单的调用,即可轻松完成系统登录鉴权!
|
||||
|
||||
|
||||
- **没有复杂的封装!不要任何的配置!先写入,后鉴权!只需这两行简单的调用,即可轻松完成系统登录鉴权!**
|
||||
|
||||
|
||||
## 🔥 框架设计思想
|
||||
## 框架设计思想
|
||||
与其它权限认证框架相比,`sa-token`尽力保证两点:
|
||||
- 上手简单:能自动化的配置全部自动化,不让你费脑子
|
||||
- 功能强大:能涵盖的功能全部涵盖,不让你用个框架还要自己给框架打各种补丁
|
||||
|
||||
|
||||
## 💦️️ 涵盖功能
|
||||
- ⚡ **登录验证** —— 轻松登录鉴权,并提供五种细分场景值
|
||||
- ⚡ **权限验证** —— 拦截违规调用,不同角色不同授权
|
||||
- ⚡ **自定义session会话** —— 专业的数据缓存中心
|
||||
- ⚡ **踢人下线** —— 将违规用户立刻清退下线
|
||||
- ⚡ **模拟他人账号** —— 实时操作任意用户状态数据
|
||||
- ⚡ **持久层扩展** —— 可集成redis、MongoDB等专业缓存中间件
|
||||
- ⚡ **多账号认证体系** —— 比如一个商城项目的user表和admin表分开鉴权
|
||||
- ⚡ **无cookie模式** —— APP、小程序等前后台分离场景
|
||||
- ⚡ **注解式鉴权** —— 优雅的将鉴权与业务代码分离
|
||||
- ⚡ **花式token生成** —— 内置六种token风格,还可自定义token生成策略
|
||||
- ⚡ **自动续签** —— 提供两种token过期策略,灵活搭配使用,还可自动续签
|
||||
- ⚡ **组件自动注入** —— 零配置与Spring等框架集成
|
||||
- ⚡ **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流
|
||||
如果上面的示例能够证明`sa-token`的简单,那么以下API则可以证明`sa-token`的强大
|
||||
``` java
|
||||
StpUtil.setLoginId(10001); // 标记当前会话登录的账号id
|
||||
StpUtil.getLoginId(); // 获取当前会话登录的账号id
|
||||
StpUtil.isLogin(); // 获取当前会话是否已经登录, 返回true或false
|
||||
StpUtil.logout(); // 当前会话注销登录
|
||||
StpUtil.logoutByLoginId(10001); // 让账号为10001的会话注销登录(踢人下线)
|
||||
StpUtil.hasRole("super-admin"); // 查询当前账号是否含有指定角色标识, 返回true或false
|
||||
StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指定权限, 返回true或false
|
||||
StpUtil.getSession(); // 获取当前账号id的Session
|
||||
StpUtil.getSessionByLoginId(10001); // 获取账号id为10001的Session
|
||||
StpUtil.getTokenValueByLoginId(10001); // 获取账号id为10001的token令牌值
|
||||
StpUtil.setLoginId(10001, "PC"); // 指定设备标识登录
|
||||
StpUtil.logoutByLoginId(10001, "PC"); // 指定设备标识进行强制注销 (不同端不受影响)
|
||||
```
|
||||
sa-token的API众多,请恕此处无法为您逐一展示,更多示例请戳官方在线文档
|
||||
|
||||
|
||||
## 🔨 贡献代码
|
||||
|
||||
|
||||
## 涵盖功能
|
||||
- **登录验证** —— 轻松登录鉴权,并提供五种细分场景值
|
||||
- **权限验证** —— 拦截违规调用,不同角色不同授权
|
||||
- **Session会话** —— 专业的数据缓存中心
|
||||
- **踢人下线** —— 将违规用户立刻清退下线
|
||||
- **模拟他人账号** —— 实时操作任意用户状态数据
|
||||
- **持久层扩展** —— 可集成redis、MongoDB等专业缓存中间件
|
||||
- **多账号认证体系** —— 比如一个商城项目的user表和admin表分开鉴权
|
||||
- **无Cookie模式** —— APP、小程序等前后台分离场景
|
||||
- **注解式鉴权** —— 优雅的将鉴权与业务代码分离
|
||||
- **花式token生成** —— 内置六种token风格,还可自定义token生成策略
|
||||
- **自动续签** —— 提供两种token过期策略,灵活搭配使用,还可自动续签
|
||||
- **同端互斥登录** —— 像QQ一样手机电脑同时在线,但是两个手机上互斥登录
|
||||
- **组件自动注入** —— 零配置与Spring等框架集成
|
||||
- **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流
|
||||
|
||||
|
||||
## 贡献代码
|
||||
sa-token欢迎大家贡献代码,为框架添砖加瓦
|
||||
1. 在github上fork一份到自己的仓库
|
||||
2. clone自己的仓库到本地电脑
|
||||
@@ -72,7 +94,7 @@ sa-token欢迎大家贡献代码,为框架添砖加瓦
|
||||
5. 等待合并
|
||||
|
||||
|
||||
## 🌱 建议贡献的地方
|
||||
## 建议贡献的地方
|
||||
- 修复源码现有bug,或增加新的实用功能
|
||||
- 完善在线文档,或者修复现有错误之处
|
||||
- 更多demo示例:比如SSM版搭建步骤
|
||||
@@ -80,11 +102,11 @@ sa-token欢迎大家贡献代码,为框架添砖加瓦
|
||||
- 如果更新实用功能,可在文档友情链接处留下自己的推广链接
|
||||
|
||||
|
||||
## 🚀 友情链接
|
||||
## 友情链接
|
||||
[**[ okhttps ]** 一个轻量级http通信框架,支持 WebSocket 以及 Stomp 协议](https://gitee.com/ejlchina-zhxu/okhttps)
|
||||
|
||||
|
||||
## 😎 交流群
|
||||
## 交流群
|
||||
QQ交流群:[1002350610 点击加入](https://jq.qq.com/?_wv=1027&k=45H977HM) ,欢迎你的加入
|
||||
|
||||
|
||||
|
||||
@@ -8,12 +8,13 @@
|
||||
- **使用**
|
||||
- [登录验证](/use/login-auth)
|
||||
- [权限验证](/use/jur-auth)
|
||||
- [session会话](/use/session)
|
||||
- [Session会话](/use/session)
|
||||
- [踢人下线](/use/kick)
|
||||
- [持久层扩展(集成redis)](/use/dao-extend)
|
||||
- [无cookie模式(前后台分离)](/use/not-cookie)
|
||||
- [持久层扩展(集成Redis)](/use/dao-extend)
|
||||
- [无Cookie模式(前后台分离)](/use/not-cookie)
|
||||
- [模拟他人](/use/mock-person)
|
||||
- [多账号验证](/use/many-account)
|
||||
- [同端互斥登录](/use/mutex-login)
|
||||
- [注解式鉴权](/use/at-check)
|
||||
- [花式token](/use/token-style)
|
||||
- [框架配置](/use/config)
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>sa-token</title>
|
||||
<title>sa-token 官方文档</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="Description">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta name="keywords" content="sa-token|sa-token框架|sa-token文档|sa-token在线文档|权限认证框架">
|
||||
<meta name="description" content="sa-token是一个JavaWeb权限认证框架,强大、简单、好用,登录验证、权限验证、自定义session会话、踢人下线、持久层扩展、无cookie模式、模拟他人账号、多账号体系、注解式鉴权、花式token、自动续签、Spring集成...,零配置开箱即用,覆盖所有应用场景,你所需要的功能,这里都有">
|
||||
<link rel="stylesheet" href="https://unpkg.com/docsify@4.11.3/lib/themes/vue.css">
|
||||
<meta name="description" content="sa-token是一个JavaWeb权限认证框架,功能全面,上手简单,登录验证、权限验证、Session会话、踢人下线、集成Redis、前后台分离、模拟他人账号、多账号体系、注解式鉴权、花式token、自动续签、同端互斥登录、Spring集成...,零配置开箱即用,覆盖所有应用场景,你所需要的功能,这里都有">
|
||||
<link rel="stylesheet" href="https://unpkg.zhimg.com/docsify@4.11.3/lib/themes/vue.css">
|
||||
<link rel="stylesheet" href="./lib/index.css">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="logo.png">
|
||||
</head>
|
||||
@@ -22,6 +22,9 @@
|
||||
<nav>
|
||||
<select onchange="location.href=this.value">
|
||||
<option value="http://sa-token.dev33.cn/doc/index.html">最新版</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.8.0/doc/index.html">v1.8.0</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.7.0/doc/index.html">v1.7.0</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.6.0/doc/index.html">v1.6.0</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.5.1/doc/index.html">v1.5.1</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.4.0/doc/index.html">v1.4.0</option>
|
||||
</select>
|
||||
@@ -35,7 +38,7 @@
|
||||
</div>
|
||||
<script>
|
||||
var name = '<img style="width: 50px; height: 50px; vertical-align: middle;" src="logo.png" alt="logo" /> ';
|
||||
name += '<b style="font-size: 24px; vertical-align: middle;">sa-token</b> <sub>v1.7.0</sub>'
|
||||
name += '<b style="font-size: 24px; vertical-align: middle;">sa-token</b> <sub>v1.9.0</sub>'
|
||||
window.$docsify = {
|
||||
name: name, // 名字
|
||||
repo: 'https://github.com/click33/sa-token', // github地址
|
||||
@@ -73,9 +76,9 @@
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<script src="https://unpkg.com/docsify@4.9.4/lib/docsify.min.js"></script>
|
||||
<script src="https://unpkg.com/docsify-copy-code@2.1.0/dist/docsify-copy-code.min.js"></script>
|
||||
<script src="https://unpkg.com/prismjs@1.19.0/components/prism-java.min.js"></script>
|
||||
<script src="https://unpkg.zhimg.com/docsify@4.9.4/lib/docsify.min.js"></script>
|
||||
<script src="https://unpkg.zhimg.com/docsify-copy-code@2.1.0/dist/docsify-copy-code.min.js"></script>
|
||||
<script src="https://unpkg.zhimg.com/prismjs@1.19.0/components/prism-java.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -14,18 +14,34 @@
|
||||
/* ============== 样式优化 ================ */
|
||||
|
||||
/* 背景变黑 */
|
||||
.main-box [data-lang]{padding: 0px !important; border-radius: 10px; overflow: hidden;}
|
||||
.main-box [class^="lang-"]{/* color: red !important; */ border: 0px red solid; padding: 1.2em; background-color: #282828; color: #FFF;}
|
||||
.main-box [class^="lang-api"]{color: #FFF;}
|
||||
.main-box [data-lang]{padding: 0px !important; border-radius: 8px; overflow: hidden;}
|
||||
.main-box [class^="lang-"]{border: 0px red solid; padding: 1.5em 1.2em;/* background-color: #282828; */ background-color: #090300; color: #FFF;}
|
||||
.main-box [data-lang]{overflow: auto;}
|
||||
/* .main-box h2{margin-top: 70px;} */
|
||||
|
||||
/* xml语言样式优化 */
|
||||
.lang-xml .token.comment{color: #CDAB53;}
|
||||
.lang-xml .token.tag *{color: #db2d20;}
|
||||
.lang-xml .token.attr-value{color: #A6E22E;}
|
||||
|
||||
/* java语言样式优化 */
|
||||
.main-box .lang-java{color: #01a252; opacity: 1;}
|
||||
.lang-java .token.keyword{color: #db2d20;}
|
||||
.lang-java .token.namespace,.lang-java .token.namespace *{color: #01A252; opacity: 1;}
|
||||
.lang-java .token.class-name,.lang-java .cm-variable{color: #55b5db; opacity: 1;}
|
||||
.lang-java .token.comment{color: #CDAB53;}
|
||||
.lang-java .token.annotation.punctuation{color: #ddd;}
|
||||
.lang-java .token.punctuation{color: #ddd;}
|
||||
|
||||
/* js语言样式优化 */
|
||||
.main-box .lang-js{color: #01a252;}
|
||||
.lang-js .token.comment{color: #CDAB53;}
|
||||
/* .lang-js .token.string{color: #fded02;} */
|
||||
.lang-js .token.string{color: #ddd;}
|
||||
.lang-js .token.punctuation{color: #ddd;}
|
||||
|
||||
|
||||
.token.string{color: #65B042;}
|
||||
.token.number{color: #2487CC;}
|
||||
.token.punctuation{color: #FFF;}
|
||||
.token.comment{color: #FFF;}
|
||||
|
||||
/* .main-box [class="lang-api"]{color: red;} */
|
||||
|
||||
/* 调整表格的响应式 */
|
||||
#main table{margin-left: 25px;}
|
||||
@media screen and (min-width: 800px) {
|
||||
#main table tr th{min-width: 150px;}
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# 更新日志
|
||||
|
||||
### 2021-1-6 @v1.9.0
|
||||
- 优化:`spring-boot-starter-data-redis` 由 `2.3.7.RELEASE` 改为 `2.3.3.RELEASE`
|
||||
- 修复:补上注解拦截器里漏掉验证`@SaCheckRole`的bug
|
||||
- 新增:新增同端互斥登录,像QQ一样手机电脑同时在线,但是两个手机上互斥登录 **[重要]**
|
||||
|
||||
|
||||
### 2021-1-2 @v1.8.0
|
||||
- 优化:优化源码注释
|
||||
- 修复:修复部分文档错别字
|
||||
- 修复:修复项目文件夹名称错误
|
||||
- 优化:优化文档配色,更舒服的代码展示
|
||||
- 新增:提供`sa-token`集成 `redis` 的 `spring-boot-starter` 方案 **[重要]**
|
||||
- 新增:新增集成 `redis` 时,以`jackson`作为序列化方案 **[重要]**
|
||||
- 新增:dao层默认实现增加定时清理过期数据功能 **[重要]**
|
||||
- 新增:新增`token专属session`, 更灵活的会话管理 **[重要]**
|
||||
- 新增:增加配置,指定在获取`token专属session`时是否必须登录
|
||||
- 新增:在无token时自动创建会话,完美兼容`token-session`会话模型! **[重要]**
|
||||
- 修改:权限码限定必须为String类型
|
||||
- 优化:注解验证模式由boolean属性改为枚举方式
|
||||
- 删除:`StpUtil`删除部分冗长API,保持API清爽性
|
||||
- 新增:新增角色验证 (角色验证与权限验证已完全分离) **[重要]**
|
||||
- 优化:移除`StpUtil.kickoutByLoginId()`API,由`logoutByLoginId`代替
|
||||
- 升级:开源协议修改为`Apache-2.0`
|
||||
|
||||
|
||||
### 2020-12-24 @v1.7.0
|
||||
- 优化:项目架构改为maven多模块形式,方便增加新模块 **[重要]**
|
||||
@@ -33,7 +57,7 @@
|
||||
|
||||
### 2020-9-7 @v1.4.0
|
||||
- 优化:修改一些函数、变量名称,使其更符合阿里java代码规范
|
||||
- 优化:`tokenValue`的读取优先级改为:`request` > `body` > `header` > `cookie`
|
||||
- 优化:`tokenValue`的读取优先级改为:`request` > `body` > `header` > `cookie` **[重要]**
|
||||
- 新增:新增`isReadCookie`配置,决定是否从`cookie`里读取`token`信息
|
||||
- 优化:如果`isReadCookie`配置为`false`,那么在登录时也不会把`cookie`写入`cookie`
|
||||
- 新增:新增`getSessionByLoginId(Object loginId, boolean isCreate)`方法
|
||||
@@ -50,7 +74,7 @@
|
||||
|
||||
|
||||
### 2020-3-7 @v1.2.0
|
||||
- 新增:新增注解式验证,可在路由方法中使用注解进行权限验证
|
||||
- 新增:新增注解式验证,可在路由方法中使用注解进行权限验证 **[重要]**
|
||||
- 参考:[注解式验证](use/at-check)
|
||||
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
------
|
||||
|
||||
## maven依赖
|
||||
## Maven依赖
|
||||
在项目中直接通过 `pom.xml` 导入 `sa-token` 的依赖即可
|
||||
``` xml
|
||||
<!-- sa-token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -21,11 +21,18 @@
|
||||
- github地址:[https://github.com/click33/sa-token](https://github.com/click33/sa-token)
|
||||
- gitee地址:[https://gitee.com/sz6/sa-token](https://gitee.com/sz6/sa-token)
|
||||
- 开源不易,求鼓励,给个`star`吧
|
||||
- 源码目录介绍
|
||||
- `sa-token-dev`: 源码
|
||||
- `sa-token-spring-boot-starter`: springboot插件化集成
|
||||
- `sa-token-demo-springboot`: springboot集成示例
|
||||
- `sa-token-doc`: 文档介绍
|
||||
- 源码目录介绍:
|
||||
```
|
||||
── sa-token
|
||||
├── sa-token-core // sa-token核心模块
|
||||
├── sa-token-spring-boot-starter // sa-token整合springboot快速集成
|
||||
├── sa-token-dao-redis // sa-token整合redis (使用jdk默认序列化方式)
|
||||
├── sa-token-dao-redis-jackson // sa-token整合redis (使用jackson序列化方式)
|
||||
├── sa-token-demo-springboot // sa-token示例
|
||||
├── sa-token-doc // sa-token开发文档
|
||||
├──pom.xml
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -34,20 +34,14 @@ spring:
|
||||
token-name: satoken
|
||||
# token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: 2592000
|
||||
# token临时有效期, 默认-1 代表不限制
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
activity-timeout: -1
|
||||
# 在多人登录同一账号时,是否共享会话 (为true时共用一个,为false时新登录挤掉旧登录)
|
||||
is-share: true
|
||||
# 是否尝试从请求体里读取token
|
||||
is-read-body: true
|
||||
# 是否尝试从header里读取token
|
||||
is-read-head: true
|
||||
# 是否尝试从cookie里读取token
|
||||
is-read-cookie: true
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
allow-concurrent-login: false
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
is-share: false
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否在初始化配置时打印版本字符画
|
||||
is-v: true
|
||||
```
|
||||
|
||||
> - 如果你习惯于 `application.properties` 类型的配置文件,那也很好办:
|
||||
@@ -60,7 +54,7 @@ spring:
|
||||
@SpringBootApplication
|
||||
public class SaTokenDemoApplication {
|
||||
public static void main(String[] args) throws JsonProcessingException {
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args); // run-->
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args);
|
||||
System.out.println("启动成功:sa-token配置如下:" + SaTokenManager.getConfig());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
---
|
||||
|
||||
- 尽管我们可以方便的一句代码完成权限验证,但是有时候我们仍希望可以将鉴权代码与我们的业务代码分离开来
|
||||
- 怎么做?
|
||||
- `sa-token`内置两个注解,帮助你使用注解完成鉴权操作
|
||||
- 怎么做?`sa-token`内置三个注解,帮助你使用注解完成鉴权操作
|
||||
|
||||
|
||||
## 1、注册拦截器
|
||||
@@ -28,29 +27,59 @@
|
||||
#### 登录验证
|
||||
|
||||
``` java
|
||||
@SaCheckLogin // 注解式鉴权:当前会话必须登录才能通过
|
||||
// 注解式鉴权:当前会话必须登录才能通过
|
||||
@SaCheckLogin
|
||||
@RequestMapping("info")
|
||||
public String info() {
|
||||
return "查询用户信息";
|
||||
}
|
||||
```
|
||||
|
||||
#### 权限验证
|
||||
#### 角色验证
|
||||
|
||||
``` java
|
||||
@SaCheckPermission("user-add") // 注解式鉴权:当前会话必须具有指定权限才能通过
|
||||
// 注解式鉴权:当前会话必须具有指定角色标识才能通过
|
||||
@SaCheckRole("super-admin")
|
||||
@RequestMapping("add")
|
||||
public String add() {
|
||||
return "用户增加";
|
||||
}
|
||||
```
|
||||
|
||||
#### 注意事项
|
||||
#### 权限验证
|
||||
|
||||
``` java
|
||||
// 注解式鉴权:当前会话必须具有指定权限才能通过
|
||||
@SaCheckPermission("user-add")
|
||||
@RequestMapping("add")
|
||||
public String add() {
|
||||
return "用户增加";
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
以上两个注解都可以加在类上,代表为这个类所有方法进行鉴权
|
||||
|
||||
|
||||
## 3、设定校验模式
|
||||
`@SaCheckRole`与`@SaCheckPermission`注解可设置校验模式,例如:
|
||||
``` java
|
||||
// 注解式鉴权:只要具有其中一个权限即可通过校验
|
||||
@RequestMapping("atJurOr")
|
||||
@SaCheckPermission(value = {"user-add", "user-all", "user-delete"}, mode = SaMode.OR)
|
||||
public AjaxJson atJurOr() {
|
||||
return AjaxJson.getSuccessData("用户信息");
|
||||
}
|
||||
```
|
||||
|
||||
## 3、扩展
|
||||
|
||||
- mode有两种取值:
|
||||
- `SaMode.AND`, 标注一组权限,会话必须全部具有才可通过校验
|
||||
- `SaMode.OR`, 标注一组权限,会话只要具有其一即可通过校验
|
||||
|
||||
|
||||
|
||||
<!-- ## 3、扩展
|
||||
- 其实在注册拦截器时,我们也可以根据路由前缀设置不同 `StpLogic`, 从而达到不同模块不同鉴权方式的目的
|
||||
- 以下为参考示例:
|
||||
``` java
|
||||
@@ -63,7 +92,7 @@
|
||||
registry.addInterceptor(new SaCheckInterceptor(StpUserUtil.stpLogic)).addPathPatterns("/user/**");
|
||||
}
|
||||
}
|
||||
```
|
||||
``` -->
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -16,20 +16,14 @@ spring:
|
||||
token-name: satoken
|
||||
# token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: 2592000
|
||||
# token临时有效期, 默认-1 代表不限制
|
||||
activity-timeout: -1
|
||||
# 在多人登录同一账号时,是否共享会话 (为true时共用一个,为false时新登录挤掉旧登录)
|
||||
is-share: true
|
||||
# 是否尝试从请求体里读取token
|
||||
is-read-body: true
|
||||
# 是否尝试从header里读取token
|
||||
is-read-head: true
|
||||
# 是否尝试从cookie里读取token
|
||||
is-read-cookie: true
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
activity-timeout: -1
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
allow-concurrent-login: false
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
is-share: false
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否在初始化配置时打印版本字符画
|
||||
is-v: true
|
||||
```
|
||||
|
||||
- 如果你习惯于 `application.properties` 类型的配置文件,那也很好办:
|
||||
@@ -44,20 +38,17 @@ spring:
|
||||
@Configuration
|
||||
public class MySaTokenConfig {
|
||||
|
||||
// 获取配置Bean (以代码的方式配置sa-token)
|
||||
// 获取配置Bean (以代码的方式配置sa-token, 此配置会覆盖yml中的配置)
|
||||
@Primary
|
||||
@Bean(name="MySaTokenConfig")
|
||||
public SaTokenConfig getSaTokenConfig() {
|
||||
SaTokenConfig config = new SaTokenConfig();
|
||||
config.setTokenName("satoken"); // token名称 (同时也是cookie名称)
|
||||
config.setTimeout(30 * 24 * 60 * 60); // token有效期,单位s 默认30天, -1代表永不过期
|
||||
config.setActivityTimeout(-1); // token临时有效期, 默认-1 代表不限制
|
||||
config.setIsShare(true); // 在多人登录同一账号时,是否共享会话 (为true时共用一个,为false时新登录挤掉旧登录)
|
||||
config.setIsReadBody(true); // 是否尝试从请求体里读取token
|
||||
config.setIsReadHead(true); // 是否尝试从header里读取token
|
||||
config.setIsReadCookie(true); // 是否尝试从cookie里读取token
|
||||
config.setTokenStyle("uuid"); // token风格
|
||||
config.setIsV(true); // 是否在初始化配置时打印版本字符画
|
||||
config.setTokenName("satoken"); // token名称 (同时也是cookie名称)
|
||||
config.setTimeout(30 * 24 * 60 * 60); // token有效期,单位s 默认30天
|
||||
config.setActivityTimeout(-1); // token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
config.setAllowConcurrentLogin(true); // 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
config.setIsShare(true); // 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
config.setTokenStyle("uuid"); // token风格
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -67,14 +58,17 @@ spring:
|
||||
|
||||
---
|
||||
### 所有可配置项
|
||||
| 参数名称 | 类型 | 默认值 | 说明 |
|
||||
| :-------- | :-------- | :-------- | :-------- |
|
||||
| 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) |
|
||||
| isShare | Boolean | true | 在多人登录同一账号时,是否共享会话(为true时共用一个,为false时新登录挤掉旧登录) |
|
||||
| isReadBody | Boolean | true | 是否尝试从请求体里读取token |
|
||||
| isReadHead | Boolean | true | 是否尝试从header里读取token |
|
||||
| isReadCookie | Boolean | true | 是否尝试从cookie里读取token |
|
||||
| tokenStyle | String | uuid | token风格, [参考:花式token](/use/token-style) |
|
||||
| isV | Boolean | true | 是否在初始化配置时打印版本字符画 |
|
||||
| 参数名称 | 类型 | 默认值 | 说明 |
|
||||
| :-------- | :-------- | :-------- | :-------- |
|
||||
| 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) |
|
||||
| allowConcurrentLogin | Boolean | true | 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) |
|
||||
| isShare | Boolean | true | 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) |
|
||||
| isReadBody | Boolean | true | 是否尝试从请求体里读取token |
|
||||
| isReadHead | Boolean | true | 是否尝试从header里读取token |
|
||||
| isReadCookie | Boolean | true | 是否尝试从cookie里读取token |
|
||||
| tokenStyle | String | uuid | token风格, [参考:花式token](/use/token-style) |
|
||||
| dataRefreshPeriod | int | 30 | 默认dao层实现类中,每次清理过期数据间隔的时间 (单位: 秒) ,默认值30秒,设置为-1代表不启动定时清理 |
|
||||
| tokenSessionCheckLogin | Boolean | true | 获取token专属session时是否必须登录 (如果配置为true,会在每次获取token专属session时校验是否登录) |
|
||||
| isV | Boolean | true | 是否在初始化配置时打印版本字符画 |
|
||||
|
||||
@@ -1,146 +1,48 @@
|
||||
# 持久层扩展
|
||||
---
|
||||
- 每次重启项目就得重新登录一遍,我想把登录数据都放在`redis`里,这样重启项目也不用重新登录,行不行?**行!**
|
||||
- 你需要做的就是重写`sa-token`的dao层实现方式,参考以下方案:
|
||||
- 每次重启项目都需要重新登录一次,我想把会话数据都放在`Redis`、`MongoDB`等专业的缓存中间件中,这样重启项目也不用重新登录,行不行?**行!**
|
||||
- sa-token 在架构设计时将数据持久操作全部抽象到接口`SaTokenDao`中,此设计可以保证开发者对数据持久层的灵活扩展
|
||||
- 除了框架内部对`SaTokenDao`提供的基于内存的默认实现,官方仓库还提供了以下扩展方案:
|
||||
|
||||
|
||||
|
||||
### 1. 首先在pom.xml引入依赖
|
||||
### 1. sa-token 整合 Redis (使用jdk默认序列化方式)
|
||||
``` xml
|
||||
<!-- SpringBoot整合redis -->
|
||||
<!-- sa-token整合redis (使用jdk默认序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-redis</artifactId>
|
||||
<version>RELEASE</version>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
```
|
||||
优点:兼容性好,缺点:session序列化后基本不可读,对开发者来讲等同于乱码
|
||||
|
||||
|
||||
### 2. sa-token 整合 Redis (使用jackson序列化方式)
|
||||
``` xml
|
||||
<!-- sa-token整合redis (使用jackson序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
```
|
||||
优点:session序列化后可读性强,可灵活手动修改,缺点:兼容性稍差
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
**请注意,无论使用哪种序列化方式,你都必须为项目提供一个Redis实例化方案,例如:**
|
||||
``` xml
|
||||
<!-- 提供redis连接池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
### 2. 实现SaTokenDao接口
|
||||
新建文件`SaTokenDaoRedis.java`,实现接口`SaTokenDao`, 并加上注解`@Component`,保证此类被springboot扫描到
|
||||
- 代码参考:
|
||||
|
||||
```java
|
||||
package com.pj.satoken;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
|
||||
/**
|
||||
* sa-token持久层的实现类 , 基于redis
|
||||
*/
|
||||
@Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token与redis的集成
|
||||
public class SaTokenDaoRedis implements SaTokenDao {
|
||||
<br><br>
|
||||
更多框架的集成方案正在更新中... (欢迎大家提交pr)
|
||||
|
||||
|
||||
// string专用
|
||||
@Autowired
|
||||
StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
// SaSession专用
|
||||
RedisTemplate<String, SaSession> redisTemplate;
|
||||
@Autowired
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void setRedisTemplate(RedisTemplate redisTemplate) {
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
|
||||
// 根据key获取value ,如果没有,则返回空
|
||||
@Override
|
||||
public String getValue(String key) {
|
||||
return stringRedisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
// 写入指定key-value键值对,并设定过期时间(单位:秒)
|
||||
@Override
|
||||
public void setValue(String key, String value, long timeout) {
|
||||
// 判断是否为永不过期
|
||||
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 = getTimeout(key);
|
||||
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键
|
||||
return;
|
||||
}
|
||||
this.setValue(key, value, expire);
|
||||
}
|
||||
|
||||
// 删除一个指定的key
|
||||
@Override
|
||||
public void deleteKey(String key) {
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
|
||||
// 获取指定key的剩余存活时间 (单位: 秒)
|
||||
@Override
|
||||
public long getTimeout(String key) {
|
||||
return stringRedisTemplate.getExpire(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 根据指定key的session,如果没有,则返回空
|
||||
@Override
|
||||
public SaSession getSession(String sessionId) {
|
||||
return redisTemplate.opsForValue().get(sessionId);
|
||||
}
|
||||
|
||||
// 将指定session持久化
|
||||
@Override
|
||||
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 updateSession(SaSession session) {
|
||||
long expire = getSessionTimeout(session.getId());
|
||||
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) { // -2 = 无此键
|
||||
return;
|
||||
}
|
||||
this.saveSession(session, expire);
|
||||
}
|
||||
|
||||
// 删除一个指定的session
|
||||
@Override
|
||||
public void deleteSession(String sessionId) {
|
||||
redisTemplate.delete(sessionId);
|
||||
}
|
||||
|
||||
// 获取指定SaSession的剩余存活时间 (单位: 秒)
|
||||
@Override
|
||||
public long getSessionTimeout(String sessionId) {
|
||||
return redisTemplate.getExpire(sessionId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
- 可参考代码:[码云:SaTokenDaoRedis.java](https://gitee.com/sz6/sa-token/blob/master/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenDaoRedis.java)
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
- 所谓权限验证,验证的核心就是当前账号是否拥有一个权限码
|
||||
- 有:就让你通过、没有:那么禁止访问
|
||||
- 再往底了说,就是每个账号都会拥有一个权限码集合,我来验证这个集合中是否包括我需要检测的那个权限码
|
||||
- 例如:当前账号拥有权限码集合:`[101, 102, "user-add", "user-get"]`,这时候我去验证权限码:`201`,则结果就是验证失败,禁止访问
|
||||
- 所以现在问题的核心就是,1、如何获取一个账号所拥有的的权限码集合,2、本次操作要验证的权限码是哪个
|
||||
- 例如:当前账号拥有权限码集合:`["user:add", "user:delete", "user:get"]`,这时候我去验证权限码:`"user:update"`,则结果就是验证失败,禁止访问
|
||||
- 所以现在问题的核心就是:
|
||||
1. 如何获取一个账号所拥有的的权限码集合
|
||||
2. 本次操作要验证的权限码是哪个
|
||||
|
||||
## 获取当前账号权限码集合
|
||||
因为每个项目的需求不同,其权限设计也千变万化,所以【获取当前账号权限码集合】这一操作不可能内置到框架中,
|
||||
@@ -30,10 +32,13 @@ import cn.dev33.satoken.stp.StpInterface;
|
||||
@Component // 保证此类被springboot扫描,完成sa-token的自定义权限验证扩展
|
||||
public class StpInterfaceImpl implements StpInterface {
|
||||
|
||||
// 返回一个账号所拥有的权限码集合
|
||||
/**
|
||||
* 返回一个账号所拥有的权限码集合
|
||||
*/
|
||||
@Override
|
||||
public List<Object> getPermissionCodeList(Object loginId, String loginKey) {
|
||||
List<Object> list = new ArrayList<Object>(); // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
|
||||
public List<String> getPermissionCodeList(Object loginId, String loginKey) {
|
||||
// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add("101");
|
||||
list.add("user-add");
|
||||
list.add("user-delete");
|
||||
@@ -43,6 +48,18 @@ public class StpInterfaceImpl implements StpInterface {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
|
||||
*/
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginKey) {
|
||||
// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add("admin");
|
||||
list.add("super-admin");
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
# 踢人下线
|
||||
所谓踢人下线,核心操作就是找到其指定`loginId`的token,并设置其失效
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 核心思想
|
||||
|
||||
- 所谓踢人下线,核心操作就是找到其指定`loginId`的token,并设置其失效
|
||||
|
||||
|
||||
## 具体API
|
||||
|
||||
#### StpUtil.logoutByLoginId(Object loginId)
|
||||
- 让指定loginId的会话注销登录(清退下线)
|
||||
让指定loginId的会话注销登录(踢人下线),例如:
|
||||
|
||||
#### StpUtil.kickoutByLoginId(Object loginId)
|
||||
- 让指定loginId的会话注销登录(踢人下线)
|
||||
``` java
|
||||
// 使账号id为10001的会话注销登录,待到10001再次访问系统时会抛出`NotLoginException`异常,场景值为-5
|
||||
StpUtil.logoutByLoginId(10001);
|
||||
```
|
||||
|
||||
## 详解
|
||||
- `logoutByLoginId` 和 `kickoutByLoginId` 都可以将用户强制下线,不同点在于:
|
||||
- `logoutByLoginId` 是将人清退,用户得到的提示是 [token无效] ,对于失效原因尚未可知 (NotLoginException场景值为-2)
|
||||
- `kickoutByLoginId` 是将人踢下线,用户可得到明确提示 [已被踢下线] (NotLoginException场景值为-5)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
## 核心思想
|
||||
- sa-token在设计时充分考虑了多账号体系时的各种逻辑
|
||||
- 以上几篇介绍的api,都是经过 `StpUtil`类的各种静态方法进行各种验证,而如果你深入它的源码,[点此阅览](https://gitee.com/sz6/sa-token/blob/master/sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpUtil.java)
|
||||
- 以上几篇介绍的api,都是经过 `StpUtil`类的各种静态方法进行各种验证,而如果你深入它的源码,[点此阅览](https://gitee.com/sz6/sa-token/blob/master/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java)
|
||||
- 就会发现,此类并没有任何代码逻辑,唯一做的事就是对成员变量`stpLogic`的各个API进行包装一下进行转发
|
||||
- 这样做有两个优点
|
||||
- `StpLogic`类的所有函数都可以被重写,按需扩展
|
||||
@@ -19,7 +19,7 @@
|
||||
1. 新建一个新的权限验证类,比如: `StpUserUtil.java`
|
||||
2. 将`StpUtil.java`类的全部代码复制粘贴到 `StpUserUtil.java`里
|
||||
3. 更改一下其 `loginKey`, 比如:
|
||||
```
|
||||
``` java
|
||||
// 底层的 StpLogic 对象
|
||||
public static StpLogic stpLogic = new StpLogic("user"); // loginKey改为user
|
||||
```
|
||||
|
||||
@@ -19,8 +19,12 @@
|
||||
- 类似API还有:
|
||||
- `StpUtil.getSessionByLoginId(Object loginId, boolean isCreate)` 获取当前会话登录id, `isCreate`代表指定是否在无`session`的情况下新建并返回
|
||||
|
||||
#### StpUtil.hasPermission(Object loginId, Object pcode)
|
||||
#### StpUtil.hasRole(Object loginId, String role)
|
||||
- 指定`loginId`是否含有指定角色
|
||||
|
||||
#### StpUtil.hasPermission(Object loginId, String permission)
|
||||
- 指定`loginId`是否含有指定权限
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# 同端互斥登录
|
||||
|
||||
如果你经常使用腾讯QQ,就会发现它的登录有如下特点:它可以手机电脑同时在线,但是不能在两个手机上同时登录一个账号 <br/>
|
||||
同端互斥登录,指的就是像腾讯QQ一样,在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线
|
||||
|
||||
---
|
||||
|
||||
## 具体API
|
||||
|
||||
在`sa-token`中如何做到同端互斥登录? <br/>
|
||||
首先在配置文件中,将 `allowConcurrentLogin` 配置为false,然后调用登录等相关接口时声明设备标识即可:
|
||||
|
||||
|
||||
#### 指定设备标识登录
|
||||
``` java
|
||||
StpUtil.setLoginId(10001, "PC"); // 指定`账号id`和`设备标识`进行登录
|
||||
```
|
||||
调用此方法登录后,同设备的会被顶下线(不同设备不受影响),再次访问系统时会抛出 `NotLoginException` 异常,场景值=`-4`
|
||||
|
||||
|
||||
#### 指定设备标识强制注销
|
||||
``` java
|
||||
StpUtil.logoutByLoginId(10001, "PC"); // 指定`账号id`和`设备标识`进行强制注销 (踢人下线)
|
||||
```
|
||||
如果第二个参数填写null或不填,代表将这个账号id所有在线端踢下线,被踢出者再次访问系统时会抛出 `NotLoginException` 异常,场景值=`-5`
|
||||
|
||||
|
||||
#### 查询当前登录的设备标识
|
||||
``` java
|
||||
StpUtil.getLoginDevice(); // 指返回当前token的登录设备
|
||||
```
|
||||
|
||||
|
||||
#### id反查token
|
||||
``` java
|
||||
StpUtil.getTokenValueByLoginId(10001, "APP"); // 获取指定loginId指定设备端的tokenValue
|
||||
```
|
||||
|
||||
|
||||
@@ -1,37 +1,58 @@
|
||||
# session会话
|
||||
# Session会话
|
||||
---
|
||||
|
||||
|
||||
## 账号session
|
||||
账号`session`指的是为每个登录账号分配的`session`
|
||||
|
||||
#### StpUtil.getSession()
|
||||
- 返回当前登录账号的`session`(必须是登录后才能调用)
|
||||
Session是会话中专业的数据缓存组件,在`sa-token`中Session分为三种, 分别是:
|
||||
- `账号Session`: 指的是框架为每个`loginId`分配的`Session`
|
||||
- `令牌Session`: 指的是框架为每个`token`分配的`Session`
|
||||
- `自定义Session`: 指的是以一个`特定的值`作为SessionId,来分配的`Session`
|
||||
|
||||
|
||||
## 自定义session
|
||||
自定义`session`指的是未登录状态下,以一个特定的值作为key,来分配的`session`
|
||||
|
||||
#### SaSessionCustomUtil.isExists(String sessionId)
|
||||
- 查询指定key的`session`,是否存在
|
||||
|
||||
#### SaSessionCustomUtil.getSessionById(String sessionId)
|
||||
- 获取指定key的`session`,如果没有,则新建并返回
|
||||
|
||||
#### SaSessionCustomUtil.delSessionById(String sessionId)
|
||||
- 删除指定key的`session`
|
||||
## 账号Session
|
||||
有关账号Session的API如下:
|
||||
``` java
|
||||
StpUtil.getSession(); // 获取当前账号id的Session (必须是登录后才能调用)
|
||||
StpUtil.getSession(true); // 获取当前账号id的Session, 并决定在Session尚未创建时,是否新建并返回
|
||||
StpUtil.getSessionByLoginId(10001); // 获取账号id为10001的Session
|
||||
StpUtil.getSessionByLoginId(10001, true); // 获取账号id为10001的Session, 并决定在Session尚未创建时,是否新建并返回
|
||||
```
|
||||
|
||||
|
||||
## session相关操作
|
||||
## 令牌Session
|
||||
有关令牌Session的API如下:
|
||||
``` java
|
||||
StpUtil.getTokenSession(); // 获取当前token的专属Session
|
||||
StpUtil.getTokenSessionByToken(token); // 获取指定token的专属Session
|
||||
```
|
||||
|
||||
|
||||
## 自定义Session
|
||||
自定义Session指的是以一个`特定的值`作为SessionId来分配的`Session`, 借助自定义Session,你可以为系统中的任意元素分配相应的session<br>
|
||||
例如以商品id作为key为每个商品分配一个Session,以便于缓存和商品相关的数据,其相关API如下:
|
||||
``` java
|
||||
SaSessionCustomUtil.isExists("goods-10001"); // 查询指定key的Session是否存在
|
||||
SaSessionCustomUtil.getSessionById("goods-10001"); // 获取指定key的Session,如果没有,则新建并返回
|
||||
SaSessionCustomUtil.getSessionById("goods-10001", false); // 获取指定key的Session,如果没有,第二个参数决定是否新建并返回
|
||||
SaSessionCustomUtil.deleteSessionById("goods-10001"); // 删除指定key的Session
|
||||
```
|
||||
在未登录状态下是否可以获取令牌Session?这取决于你配置的`tokenSessionCheckLogin`值是否为false,详见:[框架配置](/use/config?id=所有可配置项)
|
||||
|
||||
|
||||
## Session相关操作
|
||||
那么获取到的`SaSession`具体有哪些方法可供操作?
|
||||
``` java
|
||||
session.getId(); // 返回此Session的id
|
||||
session.getCreateTime(); // 返回此Session的创建时间 (时间戳)
|
||||
session.getAttribute('name'); // 在Session上获取一个值
|
||||
session.getAttribute('name', 'zhang'); // 在Session上获取一个值,并指定取不到值时返回的默认值
|
||||
session.setAttribute('name', 'zhang'); // 在Session上写入一个值
|
||||
session.removeAttribute('name'); // 在Session上移除一个值
|
||||
session.clearAttribute(); // 清空此Session的所有值
|
||||
session.containsAttribute('name'); // 获取此Session是否含有指定key (返回true或false)
|
||||
session.attributeKeys(); // 获取此Session会话上所有key (返回Set<String>)
|
||||
session.getDataMap(); // 返回此Session会话上的底层数据对象(如果更新map里的值,请调用session.update()方法避免数据过时)
|
||||
session.update(); // 将这个Session从持久库更新一下
|
||||
session.logout(); // 注销此Session会话
|
||||
```
|
||||
具体可参考`javax.servlet.http.HttpSession`,`SaSession`所含方法与其大体类似
|
||||
|
||||
#### getId()
|
||||
- 返回此`session`的id
|
||||
|
||||
#### setAttribute(String key, Object value)
|
||||
- 在此`session`对象上写入值
|
||||
|
||||
#### getAttribute(String key)
|
||||
- 在此`session`对象上查询值
|
||||
|
||||
具体可参考`javax.servlet.http.HttpSession`,`SaSession`所含方法与其大体类似
|
||||
@@ -17,7 +17,7 @@
|
||||
623368f0-ae5e-4475-a53f-93e4225f16ae
|
||||
```
|
||||
|
||||
2. token-style=`simple-uuid`,同上,uuid风格, 只不过去掉了下划线:
|
||||
2. token-style=`simple-uuid`,同上,uuid风格, 只不过去掉了中划线:
|
||||
``` html
|
||||
6fd4221395024b5f87edd34bc3258ee8
|
||||
```
|
||||
@@ -69,7 +69,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
2. 再次调用 `StpUtil.setLoginId(10001)`方法进行登录,观察其生成的token样式
|
||||
2. 再次调用 `StpUtil.setLoginId(10001)`方法进行登录,观察其生成的token样式:
|
||||
``` html
|
||||
gfuPSwZsnUhwgz08GTCH4wOgasWtc3odP4HLwXJ7NDGOximTvT4OlW19zeLH
|
||||
```
|
||||
@@ -81,6 +81,7 @@
|
||||
|
||||
1. 首先我们需要找一个合适的类库,帮助我们生成雪花算法唯一id,在此推荐 [Hutool](https://hutool.cn/docs/#/) ,在`pom.xml`里添加依赖:
|
||||
``` xml
|
||||
<!-- Hutool 一个小而全的Java工具类库 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>sa-token</title>
|
||||
<title>sa-token 官方文档</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="Description">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta name="keywords" content="sa-token|sa-token框架|sa-token文档|sa-token在线文档|权限认证框架">
|
||||
<meta name="description" content="sa-token是一个JavaWeb权限认证框架,强大、简单、好用,登录验证、权限验证、自定义session会话、踢人下线、持久层扩展、无cookie模式、模拟他人账号、多账号体系、注解式鉴权、花式token、自动续签、Spring集成...,零配置开箱即用,覆盖所有应用场景,你所需要的功能,这里都有">
|
||||
<link rel="stylesheet" href="https://unpkg.com/docsify@4.11.3/lib/themes/vue.css">
|
||||
<meta name="description" content="sa-token是一个JavaWeb权限认证框架,功能全面,上手简单,登录验证、权限验证、Session会话、踢人下线、集成Redis、前后台分离、模拟他人账号、多账号体系、注解式鉴权、花式token、自动续签、同端互斥登录、Spring集成...,零配置开箱即用,覆盖所有应用场景,你所需要的功能,这里都有">
|
||||
<link rel="stylesheet" href="https://unpkg.zhimg.com/docsify@4.11.3/lib/themes/vue.css">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="doc/logo.png">
|
||||
<link rel="stylesheet" href="index.css">
|
||||
|
||||
@@ -43,16 +43,16 @@
|
||||
<!-- 内容部分 -->
|
||||
<div class="main-box">
|
||||
<div class="content-box">
|
||||
<h1>sa-token<small>v1.7.0</small></h1>
|
||||
<h1>sa-token<small>v1.9.0</small></h1>
|
||||
<div class="sub-title">一个JavaWeb轻量级权限认证框架,功能全面,上手简单</div>
|
||||
<!-- <p>0配置开箱即用,低学习成本</p> -->
|
||||
<p>登录验证、权限验证、自定义session会话、踢人下线、持久层扩展、无cookie模式、模拟他人账号、多账号体系、注解式鉴权、花式token、自动续签、Spring集成...</p>
|
||||
<p>登录验证、权限验证、Session会话、踢人下线、集成Redis、前后台分离、模拟他人账号、多账号体系、注解式鉴权、花式token、自动续签、同端互斥登录、Spring集成...</p>
|
||||
<p>零配置开箱即用,覆盖所有应用场景,你所需要的功能,这里都有</p>
|
||||
<div class="btn-box">
|
||||
<a href="https://github.com/click33/sa-token" target="_blank">GitHub</a>
|
||||
<a href="https://gitee.com/sz6/sa-token" target="_blank">码云</a>
|
||||
<a href="http://sa-app.dev33.cn/wall.html?name=sa-token" target="_blank">需求墙</a>
|
||||
<a href="doc/" target="_self">开发文档</a>
|
||||
<a href="doc/index.html" target="_self">开发文档</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,7 +60,7 @@
|
||||
<footer>
|
||||
<p>
|
||||
<span class="copyright">Copyright © 2020 </span>
|
||||
<a href="http://www.miitbeian.gov.cn/" target="_blank">鲁ICP备18046274号-2</a>
|
||||
<a href="https://beian.miit.gov.cn/" target="_blank">鲁ICP备18046274号-2</a>
|
||||
QQ交流群:<a href="https://jq.qq.com/?_wv=1027&k=45H977HM" target="_blank">1002350610</a>
|
||||
<!-- QQ交流群:<a href="https://jq.qq.com/?_wv=1027&k=5DHN5Ib" target="_blank">782974737</a> -->
|
||||
</p>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<version>1.9.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-core</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
+2
-1
@@ -9,7 +9,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* 将此注解加到springboot启动类上,即可完成sa-token与springboot的集成
|
||||
* 将此注解加到springboot启动类上,即可完成sa-token与springboot的集成
|
||||
* <p>注: v1.7版本以上已不再需要此注解,直接引入sa-token-spring-boot-starter依赖即可
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
|
||||
+45
-43
@@ -8,6 +8,8 @@ import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
@@ -24,7 +26,7 @@ public class SaCheckInterceptor implements HandlerInterceptor {
|
||||
public StpLogic stpLogic = null;
|
||||
|
||||
/**
|
||||
* 创建,并指定一个默认的 StpLogic
|
||||
* 创建,并指定一个默认的 StpLogic
|
||||
*/
|
||||
public SaCheckInterceptor() {
|
||||
this(StpUtil.stpLogic);
|
||||
@@ -39,8 +41,6 @@ public class SaCheckInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 每次请求之前触发
|
||||
*/
|
||||
@@ -54,56 +54,58 @@ public class SaCheckInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
HandlerMethod method = (HandlerMethod ) handler;
|
||||
|
||||
// 验证登录
|
||||
// ----------- 验证登录
|
||||
if(method.hasMethodAnnotation(SaCheckLogin.class) || method.getBeanType().isAnnotationPresent(SaCheckLogin.class)) {
|
||||
stpLogic.checkLogin();
|
||||
}
|
||||
|
||||
// 获取权限注解
|
||||
SaCheckPermission scp = method.getMethodAnnotation(SaCheckPermission.class);
|
||||
if(scp == null) {
|
||||
scp = method.getBeanType().getAnnotation(SaCheckPermission.class);
|
||||
// ----------- 验证角色
|
||||
// 验证方法上的
|
||||
SaCheckRole scr = method.getMethodAnnotation(SaCheckRole.class);
|
||||
if(scr != null) {
|
||||
String[] roleArray = scr.value();
|
||||
if(scr.mode() == SaMode.AND) {
|
||||
stpLogic.checkRoleAnd(roleArray); // 必须全部都有
|
||||
} else {
|
||||
stpLogic.checkRoleOr(roleArray); // 有一个就行了
|
||||
}
|
||||
}
|
||||
if(scp == null) {
|
||||
return true;
|
||||
// 验证类上的
|
||||
scr = method.getBeanType().getAnnotation(SaCheckRole.class);
|
||||
if(scr != null) {
|
||||
String[] roleArray = scr.value();
|
||||
if(scr.mode() == SaMode.AND) {
|
||||
stpLogic.checkRoleAnd(roleArray); // 必须全部都有
|
||||
} else {
|
||||
stpLogic.checkRoleOr(roleArray); // 有一个就行了
|
||||
}
|
||||
}
|
||||
|
||||
// 开始验证权限
|
||||
Object[] codeArray = concatAbc(scp.value(), scp.valueInt(), scp.valueLong());
|
||||
if(scp.isAnd()) {
|
||||
stpLogic.checkPermissionAnd(codeArray); // 必须全部都有
|
||||
} else {
|
||||
stpLogic.checkPermissionOr(codeArray); // 有一个就行了
|
||||
// ----------- 验证权限
|
||||
// 验证方法上的
|
||||
SaCheckPermission scp = method.getMethodAnnotation(SaCheckPermission.class);
|
||||
if(scp != null) {
|
||||
String[] permissionArray = scp.value();
|
||||
if(scp.mode() == SaMode.AND) {
|
||||
stpLogic.checkPermissionAnd(permissionArray); // 必须全部都有
|
||||
} else {
|
||||
stpLogic.checkPermissionOr(permissionArray); // 有一个就行了
|
||||
}
|
||||
}
|
||||
|
||||
// 验证类上的
|
||||
scp = method.getBeanType().getAnnotation(SaCheckPermission.class);
|
||||
if(scp != null) {
|
||||
String[] permissionArray = scp.value();
|
||||
if(scp.mode() == SaMode.AND) {
|
||||
stpLogic.checkPermissionAnd(permissionArray); // 必须全部都有
|
||||
} else {
|
||||
stpLogic.checkPermissionOr(permissionArray); // 有一个就行了
|
||||
}
|
||||
}
|
||||
|
||||
// 通过验证
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 合并三个数组
|
||||
* @param a .
|
||||
* @param b .
|
||||
* @param c .
|
||||
* @return .
|
||||
*/
|
||||
private Object[] concatAbc(String[] a, int[] b, long[] c) {
|
||||
// 循环赋值
|
||||
Object[] d = new Object[a.length + b.length + c.length];
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
d[i] = a[i];
|
||||
}
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
d[a.length + i] = b[i];
|
||||
}
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
d[a.length + b.length + i] = c[i];
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
-1
@@ -20,7 +20,6 @@ public class SaTokenServletSpringImpl implements SaTokenServlet {
|
||||
return SpringMVCUtil.getRequest();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前请求的Response对象
|
||||
*/
|
||||
|
||||
+3
-6
@@ -15,7 +15,7 @@ public class SpringMVCUtil {
|
||||
|
||||
/**
|
||||
* 获取当前会话的 request
|
||||
* @return .
|
||||
* @return request
|
||||
*/
|
||||
public static HttpServletRequest getRequest() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();// 大善人SpringMVC提供的封装
|
||||
@@ -26,8 +26,8 @@ public class SpringMVCUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的 response
|
||||
* @return .
|
||||
* 获取当前会话的 response
|
||||
* @return response
|
||||
*/
|
||||
public static HttpServletResponse getResponse() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();// 大善人SpringMVC提供的封装
|
||||
@@ -37,7 +37,4 @@ public class SpringMVCUtil {
|
||||
return servletRequestAttributes.getResponse();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
package cn.dev33.satoken.config;
|
||||
|
||||
/**
|
||||
* sa-token 总配置类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenConfig {
|
||||
|
||||
private String tokenName = "satoken"; // token名称 (同时也是cookie名称)
|
||||
private long timeout = 30 * 24 * 60 * 60; // token有效期,单位s 默认30天
|
||||
private long activityTimeout = -1; // token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒, 默认-1 代表不限制 (例如可以设置为1800代表30分钟内无操作就过期)
|
||||
private Boolean isShare = true; // 在多人登录同一账号时,是否共享会话 (为true时共用一个,为false时新登录挤掉旧登录)
|
||||
private Boolean isReadBody = true; // 是否尝试从请求体里读取token
|
||||
private Boolean isReadHead = true; // 是否尝试从header里读取token
|
||||
private Boolean isReadCookie = true; // 是否尝试从cookie里读取token
|
||||
private String tokenStyle = "uuid"; // token风格
|
||||
|
||||
private Boolean isV = true; // 是否在初始化配置时打印版本字符画
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return tokenName
|
||||
*/
|
||||
public String getTokenName() {
|
||||
return tokenName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tokenName 要设置的 tokenName
|
||||
*/
|
||||
public void setTokenName(String tokenName) {
|
||||
this.tokenName = tokenName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return timeout
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeout 要设置的 timeout
|
||||
*/
|
||||
public void setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return activityTimeout
|
||||
*/
|
||||
public long getActivityTimeout() {
|
||||
return activityTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param activityTimeout 要设置的 activityTimeout
|
||||
*/
|
||||
public void setActivityTimeout(long activityTimeout) {
|
||||
this.activityTimeout = activityTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isShare
|
||||
*/
|
||||
public Boolean getIsShare() {
|
||||
return isShare;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isShare 要设置的 isShare
|
||||
*/
|
||||
public void setIsShare(Boolean isShare) {
|
||||
this.isShare = isShare;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isReadCookie
|
||||
*/
|
||||
public Boolean getIsReadCookie() {
|
||||
return isReadCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isReadCookie 要设置的 isReadCookie
|
||||
*/
|
||||
public void setIsReadCookie(Boolean isReadCookie) {
|
||||
this.isReadCookie = isReadCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isReadHead
|
||||
*/
|
||||
public Boolean getIsReadHead() {
|
||||
return isReadHead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isReadHead 要设置的 isReadHead
|
||||
*/
|
||||
public void setIsReadHead(Boolean isReadHead) {
|
||||
this.isReadHead = isReadHead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isReadBody
|
||||
*/
|
||||
public Boolean getIsReadBody() {
|
||||
return isReadBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isReadBody 要设置的 isReadBody
|
||||
*/
|
||||
public void setIsReadBody(Boolean isReadBody) {
|
||||
this.isReadBody = isReadBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return tokenStyle
|
||||
*/
|
||||
public String getTokenStyle() {
|
||||
return tokenStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tokenStyle 要设置的 tokenStyle
|
||||
*/
|
||||
public void setTokenStyle(String tokenStyle) {
|
||||
this.tokenStyle = tokenStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isV
|
||||
*/
|
||||
public Boolean getIsV() {
|
||||
return isV;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isV 要设置的 isV
|
||||
*/
|
||||
public void setIsV(Boolean isV) {
|
||||
this.isV = isV;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaTokenConfig [tokenName=" + tokenName + ", timeout=" + timeout + ", activityTimeout=" + activityTimeout
|
||||
+ ", isShare=" + isShare + ", isReadBody=" + isReadBody + ", isReadHead=" + isReadHead
|
||||
+ ", isReadCookie=" + isReadCookie + ", tokenStyle=" + tokenStyle + ", isV=" + isV + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
package cn.dev33.satoken.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
|
||||
|
||||
/**
|
||||
* session会话
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaSession implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 会话id
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 当前会话创建时间
|
||||
*/
|
||||
private long createTime;
|
||||
/**
|
||||
* 当前会话键值对
|
||||
*/
|
||||
private Map<String, Object> dataMap;
|
||||
|
||||
|
||||
/**
|
||||
* 构建一个 session对象
|
||||
* @param id sessionId
|
||||
*/
|
||||
public SaSession(String id) {
|
||||
this.id = id;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
this.dataMap = new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会话id
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前会话创建时间
|
||||
* @return 时间戳
|
||||
*/
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入一个值
|
||||
* @param key 名称
|
||||
* @param value 值
|
||||
*/
|
||||
public void setAttribute(String key, Object value) {
|
||||
dataMap.put(key, value);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取出一个值
|
||||
* @param key 名称
|
||||
* @return 值
|
||||
*/
|
||||
public Object getAttribute(String key) {
|
||||
return dataMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值,并指定取不到值时的默认值
|
||||
* @param key 名称
|
||||
* @param defaultValue 取不到值的时候返回的默认值
|
||||
* @return value
|
||||
*/
|
||||
public Object getAttribute(String key, Object defaultValue) {
|
||||
Object value = getAttribute(key);
|
||||
if(value != null) {
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 移除一个值
|
||||
* @param key 要移除的值的名字
|
||||
*/
|
||||
public void removeAttribute(String key) {
|
||||
dataMap.remove(key);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有值
|
||||
*/
|
||||
public void clearAttribute() {
|
||||
dataMap.clear();
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否含有指定key
|
||||
* @param key 是否含有指定值
|
||||
* @return 是否含有
|
||||
*/
|
||||
public boolean containsAttribute(String key) {
|
||||
return dataMap.keySet().contains(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前session会话所有key
|
||||
* @return 所有值的key列表
|
||||
*/
|
||||
public Set<String> getAttributeKeys() {
|
||||
return dataMap.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据集合(如果更新map里的值,请调用session.update()方法避免数据过时 )
|
||||
* @return 返回底层储存值的map对象
|
||||
*/
|
||||
public Map<String, Object> getDataMap() {
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将这个session从持久库更新一下
|
||||
*/
|
||||
public void update() {
|
||||
SaTokenManager.getSaTokenDao().updateSession(this);
|
||||
}
|
||||
|
||||
|
||||
// /** 注销会话(注销后,此session会话将不再存储服务器上) */
|
||||
// public void logout() {
|
||||
// SaTokenManager.getDao().delSaSession(this.id);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 开放权限验证接口,方便重写
|
||||
* @author kong
|
||||
*/
|
||||
public interface StpInterface {
|
||||
|
||||
/**
|
||||
* 返回指定login_id所拥有的权限码集合
|
||||
* @param loginId 账号id
|
||||
* @param loginKey 具体的stp标识
|
||||
* @return .
|
||||
*/
|
||||
public List<Object> getPermissionCodeList(Object loginId, String loginKey);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 权限验证接口 ,默认实现
|
||||
* @author kong
|
||||
*/
|
||||
public class StpInterfaceDefaultImpl implements StpInterface {
|
||||
|
||||
@Override
|
||||
public List<Object> getPermissionCodeList(Object loginId, String loginKey) {
|
||||
return new ArrayList<Object>();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,707 +0,0 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
|
||||
/**
|
||||
* sa-token 权限验证,逻辑 实现类
|
||||
* <p>
|
||||
* (stp = sa-token-permission 的缩写 )
|
||||
* @author kong
|
||||
*/
|
||||
public class StpLogic {
|
||||
|
||||
/**
|
||||
* 持久化的key前缀,多账号认证体系时以此值区分,比如:login、user、admin
|
||||
*/
|
||||
public String loginKey = "";
|
||||
|
||||
/**
|
||||
* 初始化StpLogic, 并制定loginKey
|
||||
* @param loginKey 账号标识
|
||||
*/
|
||||
public StpLogic(String loginKey) {
|
||||
this.loginKey = loginKey;
|
||||
}
|
||||
|
||||
|
||||
// =================== 获取token 相关 ===================
|
||||
|
||||
/**
|
||||
* 返回token名称
|
||||
* @return 此StpLogic的token名称
|
||||
*/
|
||||
public String getTokenName() {
|
||||
return getKeyTokenName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机生成一个tokenValue
|
||||
* @param loginId loginId
|
||||
* @return 生成的tokenValue
|
||||
*/
|
||||
public String randomTokenValue(Object loginId) {
|
||||
return SaTokenManager.getSaTokenAction().createToken(loginId, loginKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前tokenValue
|
||||
* @return 当前tokenValue
|
||||
*/
|
||||
public String getTokenValue(){
|
||||
// 0. 获取相应对象
|
||||
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
|
||||
SaTokenConfig config = SaTokenManager.getConfig();
|
||||
String keyTokenName = getTokenName();
|
||||
String tokenValue = null;
|
||||
|
||||
// 1. 尝试从request里读取
|
||||
if(request.getAttribute(SaTokenInsideUtil.JUST_CREATED_SAVE_KEY) != null) {
|
||||
tokenValue = String.valueOf(request.getAttribute(SaTokenInsideUtil.JUST_CREATED_SAVE_KEY));
|
||||
}
|
||||
// 2. 尝试从请求体里面读取
|
||||
if(tokenValue == null && config.getIsReadBody() == true){
|
||||
tokenValue = request.getParameter(keyTokenName);
|
||||
}
|
||||
// 3. 尝试从header力读取
|
||||
if(tokenValue == null && config.getIsReadHead() == true){
|
||||
tokenValue = request.getHeader(keyTokenName);
|
||||
}
|
||||
// 4. 尝试从cookie里读取
|
||||
if(tokenValue == null && config.getIsReadCookie() == true){
|
||||
Cookie cookie = SaTokenManager.getSaTokenCookie().getCookie(request, keyTokenName);
|
||||
if(cookie != null){
|
||||
tokenValue = cookie.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 返回
|
||||
return tokenValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的tokenValue
|
||||
* @param loginId .
|
||||
* @return .
|
||||
*/
|
||||
public String getTokenValueByLoginId(Object loginId) {
|
||||
return SaTokenManager.getSaTokenDao().getValue(getKeyLoginId(loginId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
*/
|
||||
public String getLoginKey(){
|
||||
return loginKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的token信息
|
||||
* @return token信息
|
||||
*/
|
||||
public SaTokenInfo getTokenInfo() {
|
||||
SaTokenInfo info = new SaTokenInfo();
|
||||
info.tokenName = getTokenName();
|
||||
info.tokenValue = getTokenValue();
|
||||
info.isLogin = isLogin();
|
||||
info.loginId = getLoginIdDefaultNull();
|
||||
info.loginKey = getLoginKey();
|
||||
info.tokenTimeout = getTokenTimeout();
|
||||
info.sessionTimeout = getSessionTimeout();
|
||||
info.tokenActivityTimeout = getTokenActivityTimeout();
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
// =================== 登录相关操作 ===================
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id
|
||||
* @param loginId 登录id ,建议的类型:(long | int | String)
|
||||
*/
|
||||
public void setLoginId(Object loginId) {
|
||||
|
||||
// 1、获取相应对象
|
||||
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
|
||||
SaTokenConfig config = SaTokenManager.getConfig();
|
||||
SaTokenDao dao = SaTokenManager.getSaTokenDao();
|
||||
|
||||
// 2、获取tokenValue
|
||||
String tokenValue = getTokenValueByLoginId(loginId); // 获取旧tokenValue
|
||||
if(tokenValue == null){ // 为null则创建一个新的
|
||||
tokenValue = randomTokenValue(loginId);
|
||||
} else {
|
||||
// 不为null, 并且配置不共享会话,则:将原来的会话标记为[被顶替]
|
||||
if(config.getIsShare() == false){
|
||||
dao.updateValue(getKeyTokenValue(tokenValue), NotLoginException.BE_REPLACED);
|
||||
clearLastActivity(tokenValue); // 同时清理掉[最后操作时间]
|
||||
tokenValue = randomTokenValue(loginId); // 再重新生成一个token
|
||||
}
|
||||
}
|
||||
|
||||
// 3、持久化
|
||||
dao.setValue(getKeyTokenValue(tokenValue), String.valueOf(loginId), config.getTimeout()); // token -> uid
|
||||
dao.setValue(getKeyLoginId(loginId), tokenValue, config.getTimeout()); // uid -> token
|
||||
request.setAttribute(SaTokenInsideUtil.JUST_CREATED_SAVE_KEY, tokenValue); // 保存到本次request里
|
||||
setLastActivityToNow(tokenValue); // 写入 [最后操作时间]
|
||||
if(config.getIsReadCookie() == true){
|
||||
SaTokenManager.getSaTokenCookie().addCookie(SaTokenManager.getSaTokenServlet().getResponse(), getTokenName(), tokenValue, "/", (int)config.getTimeout()); // cookie注入
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话注销登录
|
||||
*/
|
||||
public void logout() {
|
||||
// 如果连token都没有,那么无需执行任何操作
|
||||
String tokenValue = getTokenValue();
|
||||
if(tokenValue == null) {
|
||||
return;
|
||||
}
|
||||
// 如果打开了cookie模式,第一步,先把cookie清除掉
|
||||
if(SaTokenManager.getConfig().getIsReadCookie() == true){
|
||||
SaTokenManager.getSaTokenCookie().delCookie(SaTokenManager.getSaTokenServlet().getRequest(), SaTokenManager.getSaTokenServlet().getResponse(), getTokenName());
|
||||
}
|
||||
// 尝试从db中获取loginId值
|
||||
String loginId = SaTokenManager.getSaTokenDao().getValue(getKeyTokenValue(tokenValue));
|
||||
// 如果根本查不到loginId,那么也无需执行任何操作
|
||||
if(loginId == null) {
|
||||
return;
|
||||
}
|
||||
// 如果已过期或被顶替或被挤下线,那么只删除此token即可
|
||||
if(loginId.equals(NotLoginException.TOKEN_TIMEOUT) || loginId.equals(NotLoginException.BE_REPLACED) || loginId.equals(NotLoginException.KICK_OUT)) {
|
||||
return;
|
||||
}
|
||||
// 至此,已经是一个正常的loginId,开始三清
|
||||
logoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId的会话注销登录(正常注销下线)
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public void logoutByLoginId(Object loginId) {
|
||||
|
||||
// 获取相应tokenValue
|
||||
String tokenValue = getTokenValueByLoginId(loginId);
|
||||
if(tokenValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 清除相关数据
|
||||
SaTokenManager.getSaTokenDao().deleteKey(getKeyTokenValue(tokenValue)); // 清除token-id键值对
|
||||
SaTokenManager.getSaTokenDao().deleteKey(getKeyLoginId(loginId)); // 清除id-token键值对
|
||||
SaTokenManager.getSaTokenDao().deleteSession(getKeySession(loginId)); // 清除其session
|
||||
clearLastActivity(tokenValue); // 同时清理掉 [最后操作时间]
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId的会话注销登录(踢人下线)
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public void kickoutByLoginId(Object loginId) {
|
||||
|
||||
// 获取相应tokenValue
|
||||
String tokenValue = getTokenValueByLoginId(loginId);
|
||||
if(tokenValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 清除相关数据
|
||||
SaTokenManager.getSaTokenDao().updateValue(getKeyTokenValue(tokenValue), NotLoginException.KICK_OUT); // 标记:已被踢下线
|
||||
SaTokenManager.getSaTokenDao().deleteKey(getKeyLoginId(loginId)); // 清除id-token键值对
|
||||
SaTokenManager.getSaTokenDao().deleteSession(getKeySession(loginId)); // 清除其session
|
||||
clearLastActivity(tokenValue); // 同时清理掉 [最后操作时间]
|
||||
}
|
||||
|
||||
// 查询相关
|
||||
|
||||
/**
|
||||
* 获取当前会话是否已经登录
|
||||
* @return 是否已登录
|
||||
*/
|
||||
public boolean isLogin() {
|
||||
// 判断条件:不为null,并且不在异常项集合里
|
||||
return getLoginIdDefaultNull() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检验当前会话是否已经登录,如未登录,则抛出异常
|
||||
*/
|
||||
public void checkLogin() {
|
||||
getLoginId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则抛出异常
|
||||
* @return .
|
||||
*/
|
||||
public Object getLoginId() {
|
||||
// 如果获取不到token,则抛出:无token
|
||||
String tokenValue = getTokenValue();
|
||||
if(tokenValue == null) {
|
||||
throw NotLoginException.newInstance(loginKey, NotLoginException.NOT_TOKEN);
|
||||
}
|
||||
// 查找此token对应loginId, 则抛出:无效token
|
||||
String loginId = SaTokenManager.getSaTokenDao().getValue(getKeyTokenValue(tokenValue));
|
||||
if(loginId == null) {
|
||||
throw NotLoginException.newInstance(loginKey, NotLoginException.INVALID_TOKEN);
|
||||
}
|
||||
// 如果是已经过期,则抛出已经过期
|
||||
if(loginId.equals(NotLoginException.TOKEN_TIMEOUT)) {
|
||||
throw NotLoginException.newInstance(loginKey, NotLoginException.TOKEN_TIMEOUT);
|
||||
}
|
||||
// 如果是已经被顶替下去了, 则抛出:已被顶下线
|
||||
if(loginId.equals(NotLoginException.BE_REPLACED)) {
|
||||
throw NotLoginException.newInstance(loginKey, NotLoginException.BE_REPLACED);
|
||||
}
|
||||
// 如果是已经被踢下线了, 则抛出:已被踢下线
|
||||
if(loginId.equals(NotLoginException.KICK_OUT)) {
|
||||
throw NotLoginException.newInstance(loginKey, NotLoginException.KICK_OUT);
|
||||
}
|
||||
// 检查是否已经 [临时过期],同时更新[最后操作时间]
|
||||
checkActivityTimeout(tokenValue);
|
||||
updateLastActivityToNow(tokenValue);
|
||||
// 至此,返回loginId
|
||||
return loginId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回默认值
|
||||
* @param <T> 返回类型
|
||||
* @param defaultValue 默认值
|
||||
* @return 登录id
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T>T getLoginId(T defaultValue) {
|
||||
Object loginId = getLoginIdDefaultNull();
|
||||
// 如果loginId为null,则返回默认值
|
||||
if(loginId == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
// 开始尝试类型转换,只尝试三种类型:int、long、String
|
||||
if(defaultValue instanceof Integer) {
|
||||
return (T)Integer.valueOf(loginId.toString());
|
||||
}
|
||||
if(defaultValue instanceof Long) {
|
||||
return (T)Long.valueOf(loginId.toString());
|
||||
}
|
||||
if(defaultValue instanceof String) {
|
||||
return (T)loginId.toString();
|
||||
}
|
||||
return (T)loginId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回null
|
||||
* @return .
|
||||
*/
|
||||
public Object getLoginIdDefaultNull() {
|
||||
// 如果连token都是空的,则直接返回
|
||||
String tokenValue = getTokenValue();
|
||||
if(tokenValue == null) {
|
||||
return null;
|
||||
}
|
||||
// loginId为null或者在异常项里面,均视为未登录
|
||||
Object loginId = SaTokenManager.getSaTokenDao().getValue(getKeyTokenValue(tokenValue));
|
||||
if(loginId == null || NotLoginException.ABNORMAL_LIST.contains(loginId)) {
|
||||
return null;
|
||||
}
|
||||
// 如果已经[临时过期]
|
||||
if(getTokenActivityTimeoutByToken(tokenValue) == SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||
return null;
|
||||
}
|
||||
// 执行到此,证明loginId已经是个正常的账号id了
|
||||
return loginId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为String
|
||||
* @return 登录id
|
||||
*/
|
||||
public String getLoginIdAsString() {
|
||||
return String.valueOf(getLoginId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为int
|
||||
* @return 登录id
|
||||
*/
|
||||
public int getLoginIdAsInt() {
|
||||
// Object loginId = getLoginId();
|
||||
// if(loginId instanceof Integer) {
|
||||
// return (Integer)loginId;
|
||||
// }
|
||||
return Integer.valueOf(String.valueOf(getLoginId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为long
|
||||
* @return 登录id
|
||||
*/
|
||||
public long getLoginIdAsLong() {
|
||||
// Object loginId = getLoginId();
|
||||
// if(loginId instanceof Long) {
|
||||
// return (Long)loginId;
|
||||
// }
|
||||
return Long.valueOf(String.valueOf(getLoginId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定token对应的登录id,如果未登录,则返回 null
|
||||
* @param tokenValue token
|
||||
* @return 登录id
|
||||
*/
|
||||
public Object getLoginIdByToken(String tokenValue) {
|
||||
if(tokenValue != null) {
|
||||
Object loginId = SaTokenManager.getSaTokenDao().getValue(getKeyTokenValue(tokenValue));
|
||||
if(loginId != null) {
|
||||
return loginId;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// =================== session相关 ===================
|
||||
|
||||
/**
|
||||
* 获取指定key的session, 如果session尚未创建,isCreate=是否新建并返回
|
||||
* @param sessionId .
|
||||
* @param isCreate .
|
||||
* @return .
|
||||
*/
|
||||
protected SaSession getSessionBySessionId(String sessionId, boolean isCreate) {
|
||||
SaSession session = SaTokenManager.getSaTokenDao().getSession(sessionId);
|
||||
if(session == null && isCreate) {
|
||||
session = new SaSession(sessionId);
|
||||
SaTokenManager.getSaTokenDao().saveSession(session, SaTokenManager.getConfig().getTimeout());
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session, 如果没有,isCreate=是否新建并返回
|
||||
* @param loginId 登录id
|
||||
* @param isCreate 是否新建
|
||||
* @return SaSession
|
||||
*/
|
||||
public SaSession getSessionByLoginId(Object loginId, boolean isCreate) {
|
||||
return getSessionBySessionId(getKeySession(loginId), isCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session
|
||||
* @param loginId .
|
||||
* @return .
|
||||
*/
|
||||
public SaSession getSessionByLoginId(Object loginId) {
|
||||
return getSessionByLoginId(loginId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的session, 如果session尚未创建,isCreate=是否新建并返回
|
||||
* @param isCreate 是否新建
|
||||
* @return 当前会话的session
|
||||
*/
|
||||
public SaSession getSession(boolean isCreate) {
|
||||
return getSessionByLoginId(getLoginId(), isCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的session
|
||||
* @return 当前会话的session
|
||||
*/
|
||||
public SaSession getSession() {
|
||||
return getSession(true);
|
||||
}
|
||||
|
||||
|
||||
// =================== [临时过期] 验证相关 ===================
|
||||
|
||||
/**
|
||||
* 写入指定token的 [最后操作时间] 为当前时间戳
|
||||
* @param tokenValue 指定token
|
||||
*/
|
||||
protected void setLastActivityToNow(String tokenValue) {
|
||||
// 如果token == null 或者 设置了[永不过期], 则立即返回
|
||||
if(tokenValue == null || SaTokenManager.getConfig().getActivityTimeout() == SaTokenDao.NEVER_EXPIRE) {
|
||||
return;
|
||||
}
|
||||
// 将[最后操作时间]标记为当前时间戳
|
||||
SaTokenManager.getSaTokenDao().setValue(getKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()), SaTokenManager.getConfig().getTimeout());
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定token的 [最后操作时间]
|
||||
* @param tokenValue 指定token
|
||||
*/
|
||||
protected void clearLastActivity(String tokenValue) {
|
||||
// 如果token == null 或者 设置了[永不过期], 则立即返回
|
||||
if(tokenValue == null || SaTokenManager.getConfig().getActivityTimeout() == SaTokenDao.NEVER_EXPIRE) {
|
||||
return;
|
||||
}
|
||||
// 删除[最后操作时间]
|
||||
SaTokenManager.getSaTokenDao().deleteKey(getKeyLastActivityTime(tokenValue));
|
||||
// 清除标记
|
||||
SaTokenManager.getSaTokenServlet().getRequest().removeAttribute(SaTokenInsideUtil.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查指定token 是否已经[临时过期],如果已经过期则抛出异常
|
||||
* @param tokenValue 指定token
|
||||
*/
|
||||
public void checkActivityTimeout(String tokenValue) {
|
||||
// 如果token == null 或者 设置了[永不过期], 则立即返回
|
||||
if(tokenValue == null || SaTokenManager.getConfig().getActivityTimeout() == SaTokenDao.NEVER_EXPIRE) {
|
||||
return;
|
||||
}
|
||||
// 如果本次请求已经有了[检查标记], 则立即返回
|
||||
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
|
||||
if(request.getAttribute(SaTokenInsideUtil.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY) != null) {
|
||||
return;
|
||||
}
|
||||
// ------------ 验证是否已经 [临时过期]
|
||||
// 获取 [临时剩余时间]
|
||||
long timeout = getTokenActivityTimeoutByToken(tokenValue);
|
||||
// -1 代表此token已经被设置永不过期,无须继续验证
|
||||
if(timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||
return;
|
||||
}
|
||||
// -2 代表已过期,抛出异常
|
||||
if(timeout == SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||
throw NotLoginException.newInstance(loginKey, NotLoginException.TOKEN_TIMEOUT);
|
||||
}
|
||||
// --- 至此,验证已通过
|
||||
|
||||
// 打上[检查标记],标记一下当前请求已经通过验证,避免一次请求多次验证,造成不必要的性能消耗
|
||||
request.setAttribute(SaTokenInsideUtil.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前token 是否已经[临时过期],如果已经过期则抛出异常
|
||||
*/
|
||||
public void checkActivityTimeout() {
|
||||
checkActivityTimeout(getTokenValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* 续签指定token:(将 [最后操作时间] 更新为当前时间戳)
|
||||
* @param tokenValue 指定token
|
||||
*/
|
||||
public void updateLastActivityToNow(String tokenValue) {
|
||||
// 如果token == null 或者 设置了[永不过期], 则立即返回
|
||||
if(tokenValue == null || SaTokenManager.getConfig().getActivityTimeout() == SaTokenDao.NEVER_EXPIRE) {
|
||||
return;
|
||||
}
|
||||
SaTokenManager.getSaTokenDao().updateValue(getKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 续签当前token:(将 [最后操作时间] 更新为当前时间戳)
|
||||
* <h1>请注意: 即时token已经 [临时过期] 也可续签成功,
|
||||
* 如果此场景下需要提示续签失败,可在此之前调用 checkActivityTimeout() 强制检查是否过期即可 </h1>
|
||||
*/
|
||||
public void updateLastActivityToNow() {
|
||||
updateLastActivityToNow(getTokenValue());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================== 过期时间相关 ===================
|
||||
|
||||
/**
|
||||
* 获取当前登录者的token剩余有效时间 (单位: 秒)
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getTokenTimeout() {
|
||||
return SaTokenManager.getSaTokenDao().getTimeout(getKeyTokenValue(getTokenValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的token剩余有效时间 (单位: 秒)
|
||||
* @param loginId 指定loginId
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getTokenTimeoutByLoginId(Object loginId) {
|
||||
return SaTokenManager.getSaTokenDao().getTimeout(getKeyTokenValue(getTokenValueByLoginId(loginId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录者的Session剩余有效时间 (单位: 秒)
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getSessionTimeout() {
|
||||
return getSessionTimeoutByLoginId(getLoginIdDefaultNull());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的Session剩余有效时间 (单位: 秒)
|
||||
* @param loginId 指定loginId
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getSessionTimeoutByLoginId(Object loginId) {
|
||||
return SaTokenManager.getSaTokenDao().getSessionTimeout(getKeySession(loginId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前token[临时过期]剩余有效时间 (单位: 秒)
|
||||
* @return token[临时过期]剩余有效时间
|
||||
*/
|
||||
public long getTokenActivityTimeout() {
|
||||
return getTokenActivityTimeoutByToken(getTokenValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定token[临时过期]剩余有效时间 (单位: 秒)
|
||||
* @param tokenValue 指定token
|
||||
* @return token[临时过期]剩余有效时间
|
||||
*/
|
||||
public long getTokenActivityTimeoutByToken(String tokenValue) {
|
||||
// 如果token为null , 则返回 -2
|
||||
if(tokenValue == null) {
|
||||
return SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
}
|
||||
// 如果设置了永不过期, 则返回 -1
|
||||
if(SaTokenManager.getConfig().getActivityTimeout() == SaTokenDao.NEVER_EXPIRE) {
|
||||
return SaTokenDao.NEVER_EXPIRE;
|
||||
}
|
||||
// ------ 开始查询
|
||||
// 获取相关数据
|
||||
String keyLastActivityTime = getKeyLastActivityTime(tokenValue);
|
||||
String lastActivityTimeString = SaTokenManager.getSaTokenDao().getValue(keyLastActivityTime);
|
||||
// 查不到,返回-2
|
||||
if(lastActivityTimeString == null) {
|
||||
return SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
}
|
||||
// 计算相差时间
|
||||
long lastActivityTime = Long.valueOf(lastActivityTimeString);
|
||||
long apartSecond = (System.currentTimeMillis() - lastActivityTime) / 1000;
|
||||
long timeout = SaTokenManager.getConfig().getActivityTimeout() - apartSecond;
|
||||
// 如果 < 0, 代表已经过期 ,返回-2
|
||||
if(timeout < 0) {
|
||||
return SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
|
||||
// =================== 权限验证操作 ===================
|
||||
|
||||
/**
|
||||
* 指定loginId是否含有指定权限
|
||||
* @param loginId .
|
||||
* @param pcode .
|
||||
* @return .
|
||||
*/
|
||||
public boolean hasPermission(Object loginId, Object pcode) {
|
||||
List<Object> pcodeList = SaTokenManager.getStpInterface().getPermissionCodeList(loginId, loginKey);
|
||||
return !(pcodeList == null || pcodeList.contains(pcode) == false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话是否含有指定权限
|
||||
* @param pcode .
|
||||
* @return .
|
||||
*/
|
||||
public boolean hasPermission(Object pcode) {
|
||||
return hasPermission(getLoginId(), pcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 , 没有就抛出异常
|
||||
* @param pcode .
|
||||
*/
|
||||
public void checkPermission(Object pcode) {
|
||||
if(hasPermission(pcode) == false) {
|
||||
throw new NotPermissionException(pcode, this.loginKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 , 【指定多个,必须全都有】
|
||||
* @param pcodeArray .
|
||||
*/
|
||||
public void checkPermissionAnd(Object... pcodeArray){
|
||||
Object loginId = getLoginId();
|
||||
List<Object> pcodeList = SaTokenManager.getStpInterface().getPermissionCodeList(loginId, loginKey);
|
||||
for (Object pcode : pcodeArray) {
|
||||
if(pcodeList.contains(pcode) == false) {
|
||||
throw new NotPermissionException(pcode, this.loginKey); // 没有权限抛出异常
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 , 【指定多个,有一个就可以了】
|
||||
* @param pcodeArray .
|
||||
*/
|
||||
public void checkPermissionOr(Object... pcodeArray){
|
||||
Object loginId = getLoginId();
|
||||
List<Object> pcodeList = SaTokenManager.getStpInterface().getPermissionCodeList(loginId, loginKey);
|
||||
for (Object pcode : pcodeArray) {
|
||||
if(pcodeList.contains(pcode) == true) {
|
||||
return; // 有的话提前退出
|
||||
}
|
||||
}
|
||||
if(pcodeArray.length > 0) {
|
||||
throw new NotPermissionException(pcodeArray[0], this.loginKey); // 没有权限抛出异常
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =================== 返回相应key ===================
|
||||
|
||||
/**
|
||||
* 获取key:客户端 tokenName
|
||||
* @return key
|
||||
*/
|
||||
public String getKeyTokenName() {
|
||||
return SaTokenManager.getConfig().getTokenName();
|
||||
}
|
||||
/**
|
||||
* 获取key: tokenValue 持久化
|
||||
* @param tokenValue .
|
||||
* @return key
|
||||
*/
|
||||
public String getKeyTokenValue(String tokenValue) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + loginKey + ":token:" + tokenValue;
|
||||
}
|
||||
/**
|
||||
* 获取key: id 持久化
|
||||
* @param loginId .
|
||||
* @return key
|
||||
*/
|
||||
public String getKeyLoginId(Object loginId) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + loginKey + ":id:" + loginId;
|
||||
}
|
||||
/**
|
||||
* 获取key: session 持久化
|
||||
* @param loginId .
|
||||
* @return key
|
||||
*/
|
||||
public String getKeySession(Object loginId) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + loginKey + ":session:" + loginId;
|
||||
}
|
||||
/**
|
||||
* 获取key: 指定token的最后操作时间 持久化
|
||||
* @param tokenValue token
|
||||
* @return key
|
||||
*/
|
||||
public String getKeyLastActivityTime(String tokenValue) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + loginKey + ":last-activity:" + tokenValue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* 一个默认的实现
|
||||
* @author kong
|
||||
*/
|
||||
public class StpUtil {
|
||||
|
||||
/**
|
||||
* 底层的 StpLogic 对象
|
||||
*/
|
||||
public static StpLogic stpLogic = new StpLogic("login");
|
||||
|
||||
|
||||
// =================== 获取token 相关 ===================
|
||||
|
||||
/**
|
||||
* 返回token名称
|
||||
* @return 此StpLogic的token名称
|
||||
*/
|
||||
public static String getTokenName() {
|
||||
return stpLogic.getTokenName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前tokenValue
|
||||
* @return 当前tokenValue
|
||||
*/
|
||||
public static String getTokenValue() {
|
||||
return stpLogic.getTokenValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的tokenValue
|
||||
* @param loginId .
|
||||
* @return .
|
||||
*/
|
||||
public static String getTokenValueByLoginId(Object loginId) {
|
||||
return stpLogic.getTokenValueByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
*/
|
||||
public static String getLoginKey(){
|
||||
return stpLogic.getLoginKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的token信息
|
||||
* @return token信息
|
||||
*/
|
||||
public static SaTokenInfo getTokenInfo() {
|
||||
return stpLogic.getTokenInfo();
|
||||
}
|
||||
|
||||
// =================== 登录相关操作 ===================
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id
|
||||
* @param loginId 登录id ,建议的类型:(long | int | String)
|
||||
*/
|
||||
public static void setLoginId(Object loginId) {
|
||||
stpLogic.setLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话注销登录
|
||||
*/
|
||||
public static void logout() {
|
||||
stpLogic.logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId的会话注销登录(正常注销下线)
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public static void logoutByLoginId(Object loginId) {
|
||||
stpLogic.logoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId的会话注销登录(踢人下线)
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public static void kickoutByLoginId(Object loginId) {
|
||||
stpLogic.kickoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
// 查询相关
|
||||
|
||||
/**
|
||||
* 获取当前会话是否已经登录
|
||||
* @return 是否已登录
|
||||
*/
|
||||
public static boolean isLogin() {
|
||||
return stpLogic.isLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检验当前会话是否已经登录,如未登录,则抛出异常
|
||||
*/
|
||||
public static void checkLogin() {
|
||||
getLoginId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则抛出异常
|
||||
* @return .
|
||||
*/
|
||||
public static Object getLoginId() {
|
||||
return stpLogic.getLoginId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回默认值
|
||||
* @param <T> 返回类型
|
||||
* @param defaultValue 默认值
|
||||
* @return 登录id
|
||||
*/
|
||||
public static <T> T getLoginId(T defaultValue) {
|
||||
return stpLogic.getLoginId(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回null
|
||||
* @return .
|
||||
*/
|
||||
public static Object getLoginIdDefaultNull() {
|
||||
return stpLogic.getLoginIdDefaultNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为String
|
||||
* @return 登录id
|
||||
*/
|
||||
public static String getLoginIdAsString() {
|
||||
return stpLogic.getLoginIdAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为int
|
||||
* @return 登录id
|
||||
*/
|
||||
public static int getLoginIdAsInt() {
|
||||
return stpLogic.getLoginIdAsInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为long
|
||||
* @return 登录id
|
||||
*/
|
||||
public static long getLoginIdAsLong() {
|
||||
return stpLogic.getLoginIdAsLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定token对应的登录id,如果未登录,则返回 null
|
||||
* @param tokenValue token
|
||||
* @return 登录id
|
||||
*/
|
||||
public static Object getLoginIdByToken(String tokenValue) {
|
||||
return stpLogic.getLoginIdByToken(tokenValue);
|
||||
}
|
||||
|
||||
|
||||
// =================== session相关 ===================
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session, 如果没有,isCreate=是否新建并返回
|
||||
* @param loginId 登录id
|
||||
* @param isCreate 是否新建
|
||||
* @return SaSession
|
||||
*/
|
||||
public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) {
|
||||
return stpLogic.getSessionByLoginId(loginId, isCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session
|
||||
* @param loginId .
|
||||
* @return .
|
||||
*/
|
||||
public static SaSession getSessionByLoginId(Object loginId) {
|
||||
return stpLogic.getSessionByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的session, 如果没有,isCreate=是否新建并返回
|
||||
* @param isCreate 是否新建
|
||||
* @return 当前会话的session
|
||||
*/
|
||||
public static SaSession getSession(boolean isCreate) {
|
||||
return stpLogic.getSession(isCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的session
|
||||
* @return .
|
||||
*/
|
||||
public static SaSession getSession() {
|
||||
return stpLogic.getSession();
|
||||
}
|
||||
|
||||
|
||||
// =================== [临时过期] 验证相关 ===================
|
||||
|
||||
/**
|
||||
* 检查当前token 是否已经[临时过期],如果已经过期则抛出异常
|
||||
*/
|
||||
public static void checkActivityTimeout() {
|
||||
stpLogic.checkActivityTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 续签当前token:(将 [最后操作时间] 更新为当前时间戳)
|
||||
* <h1>请注意: 即时token已经 [临时过期] 也可续签成功,
|
||||
* 如果此场景下需要提示续签失败,可在此之前调用 checkActivityTimeout() 强制检查是否过期即可 </h1>
|
||||
*/
|
||||
public static void updateLastActivityToNow() {
|
||||
stpLogic.updateLastActivityToNow();
|
||||
}
|
||||
|
||||
|
||||
// =================== 过期时间相关 ===================
|
||||
|
||||
/**
|
||||
* 获取当前登录者的token剩余有效时间 (单位: 秒)
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public static long getTimeout() {
|
||||
return stpLogic.getTokenTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的token剩余有效时间 (单位: 秒)
|
||||
* @param loginId 指定loginId
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public static long getTimeoutByLoginId(Object loginId) {
|
||||
return stpLogic.getTokenTimeoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录者的Session剩余有效时间 (单位: 秒)
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public static long getSessionTimeout() {
|
||||
return stpLogic.getSessionTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的Session剩余有效时间 (单位: 秒)
|
||||
* @param loginId 指定loginId
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public static long getSessionTimeoutByLoginId(Object loginId) {
|
||||
return stpLogic.getSessionTimeoutByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前token[临时过期]剩余有效时间 (单位: 秒)
|
||||
* @return token[临时过期]剩余有效时间
|
||||
*/
|
||||
public static long getTokenActivityTimeout() {
|
||||
return stpLogic.getTokenActivityTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定token[临时过期]剩余有效时间 (单位: 秒)
|
||||
* @param tokenValue 指定token
|
||||
* @return token[临时过期]剩余有效时间
|
||||
*/
|
||||
public static long getTokenActivityTimeoutByToken(String tokenValue) {
|
||||
return stpLogic.getTokenActivityTimeoutByToken(tokenValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================== 权限验证操作 ===================
|
||||
|
||||
/**
|
||||
* 指定loginId是否含有指定权限
|
||||
* @param loginId .
|
||||
* @param pcode .
|
||||
* @return .
|
||||
*/
|
||||
public static boolean hasPermission(Object loginId, Object pcode) {
|
||||
return stpLogic.hasPermission(loginId, pcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话是否含有指定权限
|
||||
* @param pcode .
|
||||
* @return .
|
||||
*/
|
||||
public static boolean hasPermission(Object pcode) {
|
||||
return stpLogic.hasPermission(pcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 , 没有就抛出异常
|
||||
* @param pcode .
|
||||
*/
|
||||
public static void checkPermission(Object pcode) {
|
||||
stpLogic.checkPermission(pcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 , 【指定多个,必须全都有】
|
||||
* @param pcodeArray .
|
||||
*/
|
||||
public static void checkPermissionAnd(Object... pcodeArray) {
|
||||
stpLogic.checkPermissionAnd(pcodeArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 , 【指定多个,有一个就可以了】
|
||||
* @param pcodeArray .
|
||||
*/
|
||||
public static void checkPermissionOr(Object... pcodeArray) {
|
||||
stpLogic.checkPermissionOr(pcodeArray);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user