!6 v1.9.0 版本更新

Merge pull request !6 from 省长/dev
This commit is contained in:
省长 2021-01-06 02:43:35 +08:00 committed by Gitee
commit 97a5fb2f40
24 changed files with 382 additions and 162 deletions

View File

@ -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.8.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.8.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,7 +16,7 @@
---
## 😘 在线资料
## 在线资料
- [官网首页http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
@ -27,8 +27,8 @@
- [开源不易求鼓励点个star吧](https://github.com/click33/sa-token)
## sa-token是什么
**sa-token是一个JavaWeb轻量级权限认证框架其API调用非常简单有多简单呢以登录验证为例你只需要**
## sa-token是什么
sa-token是一个JavaWeb轻量级权限认证框架其API调用非常简单有多简单呢以登录验证为例你只需要
``` java
// 在登录时写入当前会话的账号id
@ -39,16 +39,16 @@ StpUtil.checkLogin();
```
**没有复杂的封装!不要任何的配置!只需这两行简单的调用,即可轻松完成系统登录鉴权!**
没有复杂的封装!不要任何的配置!只需这两行简单的调用,即可轻松完成系统登录鉴权!
## 🔥 框架设计思想
## 框架设计思想
与其它权限认证框架相比,`sa-token`尽力保证两点:
- 上手简单:能自动化的配置全部自动化,不让你费脑子
- 功能强大:能涵盖的功能全部涵盖,不让你用个框架还要自己给框架打各种补丁
**如果上面的示例能够证明`sa-token`的简单那么以下API则可以证明`sa-token`的强大**
如果上面的示例能够证明`sa-token`的简单那么以下API则可以证明`sa-token`的强大
``` java
StpUtil.setLoginId(10001); // 标记当前会话登录的账号id
StpUtil.getLoginId(); // 获取当前会话登录的账号id
@ -60,13 +60,15 @@ StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指定权
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众多请恕此处无法为您逐一展示更多示例请戳官方在线文档**
sa-token的API众多请恕此处无法为您逐一展示更多示例请戳官方在线文档
## 💦️️ 涵盖功能
## 涵盖功能
- **登录验证** —— 轻松登录鉴权,并提供五种细分场景值
- **权限验证** —— 拦截违规调用,不同角色不同授权
- **Session会话** —— 专业的数据缓存中心
@ -78,11 +80,12 @@ StpUtil.getTokenValueByLoginId(10001); // 获取账号id为10001的token令牌
- **注解式鉴权** —— 优雅的将鉴权与业务代码分离
- **花式token生成** —— 内置六种token风格还可自定义token生成策略
- **自动续签** —— 提供两种token过期策略灵活搭配使用还可自动续签
- **同端互斥登录** —— 像QQ一样手机电脑同时在线但是两个手机上互斥登录
- **组件自动注入** —— 零配置与Spring等框架集成
- **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流
## 🔨 贡献代码
## 贡献代码
sa-token欢迎大家贡献代码为框架添砖加瓦
1. 在github上fork一份到自己的仓库
2. clone自己的仓库到本地电脑
@ -91,7 +94,7 @@ sa-token欢迎大家贡献代码为框架添砖加瓦
5. 等待合并
## 🌱 建议贡献的地方
## 建议贡献的地方
- 修复源码现有bug或增加新的实用功能
- 完善在线文档,或者修复现有错误之处
- 更多demo示例比如SSM版搭建步骤
@ -99,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) ,欢迎你的加入

View File

@ -8,7 +8,7 @@
<groupId>cn.dev33</groupId>
<artifactId>sa-token-parent</artifactId>
<packaging>pom</packaging>
<version>1.8.0</version>
<version>1.9.0</version>
<!-- 项目介绍 -->
<name>sa-token</name>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-parent</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>
<packaging>jar</packaging>

View File

@ -31,18 +31,18 @@ public class SaTokenInfo {
/** token专属session剩余有效时间 (单位: 秒) */
public long tokenSessionTimeout;
/**
* token剩余无操作有效时间
*/
public long tokenActivityTimeout;
/** 当前登录设备 */
public String loginDevice;
/**
* @return tokenName token名称
* @return tokenName
*/
public String getTokenName() {
return tokenName;
@ -50,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;
}
/**
@ -66,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;
}
/**
@ -82,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;
}
/**
@ -98,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;
}
/**
@ -114,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
*/
@ -130,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;
}
/**
@ -146,11 +134,9 @@ public class SaTokenInfo {
/**
* @param sessionTimeout 要设置的 sessionTimeout
* @return 对象自身
*/
public SaTokenInfo setSessionTimeout(long sessionTimeout) {
public void setSessionTimeout(long sessionTimeout) {
this.sessionTimeout = sessionTimeout;
return this;
}
/**
@ -162,13 +148,11 @@ public class SaTokenInfo {
/**
* @param tokenSessionTimeout 要设置的 tokenSessionTimeout
* @return 对象自身
*/
public SaTokenInfo setTokenSessionTimeout(long tokenSessionTimeout) {
public void setTokenSessionTimeout(long tokenSessionTimeout) {
this.tokenSessionTimeout = tokenSessionTimeout;
return this;
}
/**
* @return tokenActivityTimeout
*/
@ -178,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;
}
@ -193,8 +189,9 @@ public class SaTokenInfo {
return "SaTokenInfo [tokenName=" + tokenName + ", tokenValue=" + tokenValue + ", isLogin=" + isLogin
+ ", loginId=" + loginId + ", loginKey=" + loginKey + ", tokenTimeout=" + tokenTimeout
+ ", sessionTimeout=" + sessionTimeout + ", tokenSessionTimeout=" + tokenSessionTimeout
+ ", tokenActivityTimeout=" + tokenActivityTimeout + "]";
+ ", tokenActivityTimeout=" + tokenActivityTimeout + ", loginDevice=" + loginDevice + "]";
}
@ -208,6 +205,4 @@ public class SaTokenInfo {
}

View File

@ -119,6 +119,7 @@ public class StpLogic {
info.sessionTimeout = getSessionTimeout();
info.tokenSessionTimeout = getTokenSessionTimeout();
info.tokenActivityTimeout = getTokenActivityTimeout();
info.loginDevice = getLoginDevice();
return info;
}
@ -130,11 +131,23 @@ public class StpLogic {
* @param loginId 登录id建议的类型long | int | String
*/
public void setLoginId(Object loginId) {
setLoginId(loginId, SaTokenConsts.DEFAULT_LOGIN_DEVICE);
}
/**
* 在当前会话上登录id
* @param loginId 登录id建议的类型long | int | String
* @param device 设备标识
*/
public void setLoginId(Object loginId, String device) {
// ------ 0如果当前会话已经登录上了此LoginId则立即返回
// ------ 0如果当前会话已经登录上了此LoginId且登录设备相同则立即返回
Object loggedId = getLoginIdDefaultNull();
if(loggedId != null && loggedId.toString().equals(loginId.toString())) {
return;
String loggedDevice = getLoginDevice();
if(loggedDevice != null && loggedDevice.equals(device)) {
return;
}
}
// ------ 1获取相应对象
@ -148,18 +161,20 @@ public class StpLogic {
if(config.getAllowConcurrentLogin() == true) {
// 如果配置为共享token, 则尝试从session签名记录里取出token
if(config.getIsShare() == true) {
tokenValue = getTokenValueByLoginId(loginId);
tokenValue = getTokenValueByLoginId(loginId, device);
}
} else {
// --- 如果不允许并发登录
// 如果此时[id-session]不为null说明此账号在其他地正在登录现在需要先把其它地的token标记为被顶下线
// 如果此时[id-session]不为null说明此账号在其他地正在登录现在需要先把其它地的同设备token标记为被顶下线
SaSession session = getSessionByLoginId(loginId, false);
if(session != null) {
List<String> tokenValueList = getTokenValueListByLoginId(loginId);
for (String token : tokenValueList) {
dao.updateValue(getKeyTokenValue(token), NotLoginException.BE_REPLACED); // 1. 将此token 标记为已顶替
clearLastActivity(token); // 2. 清理掉[token-最后操作时间]
session.removeTokenSign(token); // 3. 清理账号session上的token签名
List<TokenSign> tokenSignList = session.getTokenSignList();
for (TokenSign tokenSign : tokenSignList) {
if(tokenSign.getDevice().equals(device)) {
dao.updateValue(getKeyTokenValue(tokenSign.getValue()), NotLoginException.BE_REPLACED); // 1. 将此token 标记为已顶替
clearLastActivity(tokenSign.getValue()); // 2. 清理掉[token-最后操作时间]
session.removeTokenSign(tokenSign.getValue()); // 3. 清理账号session上的token签名记录
}
}
}
}
@ -176,7 +191,7 @@ public class StpLogic {
dao.updateSessionTimeout(session.getId(), config.getTimeout());
}
// 在session上记录token签名
session.addTokenSign(new TokenSign(tokenValue, SaTokenConsts.DEFAULT_LOGIN_DEVICE));
session.addTokenSign(new TokenSign(tokenValue, device));
// ------ 4. 持久化其它数据
dao.setValue(getKeyTokenValue(tokenValue), String.valueOf(loginId), config.getTimeout()); // token -> uid
@ -187,6 +202,7 @@ public class StpLogic {
}
}
/**
* 当前会话注销登录
*/
@ -203,6 +219,7 @@ public class StpLogic {
logoutByTokenValue(tokenValue);
}
/**
* 指定token的会话注销登录
* @param tokenValue 指定token
@ -229,12 +246,23 @@ public class StpLogic {
session.logoutByTokenSignCountToZero();
}
/**
* 指定loginId的会话注销登录踢人下线
* <p> 当对方再次访问系统时会抛出NotLoginException异常场景值=-2
* @param loginId 账号id
*/
public void logoutByLoginId(Object loginId) {
logoutByLoginId(loginId, null);
}
/**
* 指定loginId指定设备的会话注销登录踢人下线
* <p> 当对方再次访问系统时会抛出NotLoginException异常场景值=-2
* @param loginId 账号id
* @param device 设备标识 (填null代表所有注销设备)
*/
public void logoutByLoginId(Object loginId, String device) {
// 先获取这个账号的[id-session], 如果为null则不执行任何操作
SaSession session = getSessionByLoginId(loginId);
if(session == null) {
@ -244,14 +272,16 @@ public class StpLogic {
// 循环token签名列表开始删除相关信息
List<TokenSign> tokenSignList = session.getTokenSignList();
for (TokenSign tokenSign : tokenSignList) {
// 1. 获取token
String tokenValue = tokenSign.getValue();
// 2. 清理掉[token-最后操作时间]
clearLastActivity(tokenValue);
// 3. 标记已被踢下线
SaTokenManager.getSaTokenDao().updateValue(getKeyTokenValue(tokenValue), NotLoginException.KICK_OUT); // 标记已被踢下线
// 4. 清理账号session上的token签名
session.removeTokenSign(tokenValue);
if(device == null || tokenSign.getDevice().equals(device)) {
// 1. 获取token
String tokenValue = tokenSign.getValue();
// 2. 清理掉[token-最后操作时间]
clearLastActivity(tokenValue);
// 3. 标记已被踢下线
SaTokenManager.getSaTokenDao().updateValue(getKeyTokenValue(tokenValue), NotLoginException.KICK_OUT); // 标记已被踢下线
// 4. 清理账号session上的token签名
session.removeTokenSign(tokenValue);
}
}
// 尝试注销session
session.logoutByTokenSignCountToZero();
@ -269,6 +299,7 @@ public class StpLogic {
return getLoginIdDefaultNull() != null;
}
/**
* 检验当前会话是否已经登录如未登录则抛出异常
*/
@ -276,6 +307,7 @@ public class StpLogic {
getLoginId();
}
/**
* 获取当前会话账号id, 如果未登录则抛出异常
* @return 账号id
@ -310,7 +342,8 @@ public class StpLogic {
return loginId;
}
/**
/**
* 获取当前会话登录id, 如果未登录则返回默认值
* @param <T> 返回类型
* @param defaultValue 默认值
@ -336,7 +369,8 @@ public class StpLogic {
return (T)loginId;
}
/**
/**
* 获取当前会话登录id, 如果未登录则返回null
* @return 账号id
*/
@ -359,6 +393,7 @@ public class StpLogic {
return loginId;
}
/**
* 获取当前会话登录id, 并转换为String
* @return 账号id
@ -367,7 +402,8 @@ public class StpLogic {
return String.valueOf(getLoginId());
}
/**
/**
* 获取当前会话登录id, 并转换为int
* @return 账号id
*/
@ -379,7 +415,8 @@ public class StpLogic {
return Integer.valueOf(String.valueOf(getLoginId()));
}
/**
/**
* 获取当前会话登录id, 并转换为long
* @return 账号id
*/
@ -391,6 +428,7 @@ public class StpLogic {
return Long.valueOf(String.valueOf(getLoginId()));
}
/**
* 获取指定token对应的登录id如果未登录则返回 null
* @param tokenValue token
@ -424,6 +462,7 @@ public class StpLogic {
return session;
}
/**
* 获取指定loginId的session, 如果session尚未创建isCreate=是否新建并返回
* @param loginId 账号id
@ -434,6 +473,7 @@ public class StpLogic {
return getSessionBySessionId(getKeySession(loginId), isCreate);
}
/**
* 获取指定loginId的session如果session尚未创建则新建并返回
* @param loginId 账号id
@ -443,6 +483,7 @@ public class StpLogic {
return getSessionByLoginId(loginId, true);
}
/**
* 获取当前会话的session, 如果session尚未创建isCreate=是否新建并返回
* @param isCreate 是否新建
@ -452,6 +493,7 @@ public class StpLogic {
return getSessionByLoginId(getLoginId(), isCreate);
}
/**
* 获取当前会话的session如果session尚未创建则新建并返回
* @return 当前会话的session
@ -463,6 +505,7 @@ public class StpLogic {
// =================== token专属session ===================
/**
* 获取指定token的专属session如果session尚未创建isCreate代表是否新建并返回
* @param tokenValue token值
@ -473,6 +516,7 @@ public class StpLogic {
return getSessionBySessionId(getKeyTokenSession(tokenValue), isCreate);
}
/**
* 获取指定token的专属session如果session尚未创建则新建并返回
* @param tokenValue token值
@ -482,6 +526,7 @@ public class StpLogic {
return getSessionBySessionId(getKeyTokenSession(tokenValue), true);
}
/**
* 获取当前token的专属-session如果session尚未创建isCreate代表是否新建并返回
* @param isCreate 是否新建
@ -502,6 +547,7 @@ public class StpLogic {
return getSessionBySessionId(getKeyTokenSession(getTokenValue()), isCreate);
}
/**
* 获取当前token的专属-session如果session尚未创建则新建并返回
* @return session会话
@ -513,7 +559,8 @@ public class StpLogic {
// =================== [临时过期] 验证相关 ===================
/**
/**
* 写入指定token的 [最后操作时间] 为当前时间戳
* @param tokenValue 指定token
*/
@ -526,6 +573,7 @@ public class StpLogic {
SaTokenManager.getSaTokenDao().setValue(getKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()), getConfig().getTimeout());
}
/**
* 清除指定token的 [最后操作时间]
* @param tokenValue 指定token
@ -541,6 +589,7 @@ public class StpLogic {
SaTokenManager.getSaTokenServlet().getRequest().removeAttribute(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY);
}
/**
* 检查指定token 是否已经[临时过期]如果已经过期则抛出异常
* @param tokenValue 指定token
@ -572,6 +621,7 @@ public class StpLogic {
request.setAttribute(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY, true);
}
/**
* 检查当前token 是否已经[临时过期]如果已经过期则抛出异常
*/
@ -579,6 +629,7 @@ public class StpLogic {
checkActivityTimeout(getTokenValue());
}
/**
* 续签指定token( [最后操作时间] 更新为当前时间戳)
* @param tokenValue 指定token
@ -591,6 +642,7 @@ public class StpLogic {
SaTokenManager.getSaTokenDao().updateValue(getKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()));
}
/**
* 续签当前token( [最后操作时间] 更新为当前时间戳)
* <h1>请注意: 即时token已经 [临时过期] 也可续签成功
@ -827,7 +879,6 @@ public class StpLogic {
// =================== id 反查token 相关操作 ===================
/**
* 获取指定loginId的tokenValue
* <p> 在配置为允许并发登录时此方法只会返回队列的最后一个token
@ -836,16 +887,38 @@ public class StpLogic {
* @return token值
*/
public String getTokenValueByLoginId(Object loginId) {
List<String> tokenValueList = getTokenValueListByLoginId(loginId);
return getTokenValueByLoginId(loginId, SaTokenConsts.DEFAULT_LOGIN_DEVICE);
}
/**
* 获取指定loginId指定设备端的tokenValue
* <p> 在配置为允许并发登录时此方法只会返回队列的最后一个token
* 如果你需要返回此账号id的所有token请调用 getTokenValueListByLoginId
* @param loginId 账号id
* @param device 设备标识
* @return token值
*/
public String getTokenValueByLoginId(Object loginId, String device) {
List<String> tokenValueList = getTokenValueListByLoginId(loginId, device);
return tokenValueList.size() == 0 ? null : tokenValueList.get(tokenValueList.size() - 1);
}
/**
* 获取指定loginId的tokenValue
* 获取指定loginId的tokenValue集合
* @param loginId 账号id
* @return 此loginId的所有相关token
*/
public List<String> getTokenValueListByLoginId(Object loginId) {
return getTokenValueListByLoginId(loginId, SaTokenConsts.DEFAULT_LOGIN_DEVICE);
}
/**
* 获取指定loginId指定设备端的tokenValue 集合
* @param loginId 账号id
* @param device 设备标识
* @return 此loginId的所有相关token
*/
public List<String> getTokenValueListByLoginId(Object loginId, String device) {
// 如果session为null的话直接返回空集合
SaSession session = getSessionByLoginId(loginId, false);
if(session == null) {
@ -855,11 +928,42 @@ public class StpLogic {
List<TokenSign> tokenSignList = session.getTokenSignList();
List<String> tokenValueList = new ArrayList<>();
for (TokenSign tokenSign : tokenSignList) {
tokenValueList.add(tokenSign.getValue());
if(tokenSign.getDevice().equals(device)) {
tokenValueList.add(tokenSign.getValue());
}
}
return tokenValueList;
}
/**
* 返回当前token的登录设备
* @return 当前令牌的登录设备
*/
public String getLoginDevice() {
// 如果没有token直接返回
String tokenValue = getTokenValue();
if(tokenValue == null) {
return null;
}
// 如果还未登录直接返回 null
if(isLogin() == false) {
return null;
}
// 如果session为null的话直接返回 null
SaSession session = getSession(false);
if(session == null) {
return null;
}
// 遍历解析
List<TokenSign> tokenSignList = session.getTokenSignList();
for (TokenSign tokenSign : tokenSignList) {
if(tokenSign.getValue().equals(tokenValue)) {
return tokenSign.getDevice();
}
}
return null;
}
// =================== 返回相应key ===================
@ -870,6 +974,7 @@ public class StpLogic {
public String getKeyTokenName() {
return getConfig().getTokenName();
}
/**
* 获取key tokenValue 持久化 token-id
* @param tokenValue token值
@ -878,6 +983,7 @@ public class StpLogic {
public String getKeyTokenValue(String tokenValue) {
return getConfig().getTokenName() + ":" + loginKey + ":token:" + tokenValue;
}
/**
* 获取key session 持久化
* @param loginId 账号id
@ -886,6 +992,7 @@ public class StpLogic {
public String getKeySession(Object loginId) {
return getConfig().getTokenName() + ":" + loginKey + ":session:" + loginId;
}
/**
* 获取key tokenValue的专属session
* @param tokenValue token值
@ -894,6 +1001,7 @@ public class StpLogic {
public String getKeyTokenSession(String tokenValue) {
return getConfig().getTokenName() + ":" + loginKey + ":token-session:" + tokenValue;
}
/**
* 获取key 指定token的最后操作时间 持久化
* @param tokenValue token值

View File

@ -61,6 +61,15 @@ public class StpUtil {
stpLogic.setLoginId(loginId);
}
/**
* 在当前会话上登录id
* @param loginId 登录id建议的类型long | int | String
* @param device 设备标识
*/
public static void setLoginId(Object loginId, String device) {
stpLogic.setLoginId(loginId, device);
}
/**
* 当前会话注销登录
*/
@ -85,6 +94,16 @@ public class StpUtil {
stpLogic.logoutByLoginId(loginId);
}
/**
* 指定loginId指定设备的会话注销登录踢人下线
* <p> 当对方再次访问系统时会抛出NotLoginException异常场景值=-2
* @param loginId 账号id
* @param device 设备标识
*/
public static void logoutByLoginId(Object loginId, String device) {
stpLogic.logoutByLoginId(loginId, device);
}
// 查询相关
@ -381,15 +400,44 @@ public class StpUtil {
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
* 获取指定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();
}
}

View File

@ -10,7 +10,7 @@ public class SaTokenConsts {
/**
* sa-token 版本号
*/
public static final String VERSION_NO = "v1.8.0";
public static final String VERSION_NO = "v1.9.0";
/**
* sa-token 开源地址

View File

@ -7,7 +7,7 @@
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-parent</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>
<packaging>jar</packaging>
@ -20,13 +20,13 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency>
<!-- RedisTemplate 相关操作API -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.3.7.RELEASE</version>
<version>2.3.3.RELEASE</version>
</dependency>
</dependencies>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-parent</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>
<packaging>jar</packaging>
@ -20,13 +20,13 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency>
<!-- RedisTemplate 相关操作API -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.3.7.RELEASE</version>
<version>2.3.3.RELEASE</version>
</dependency>
</dependencies>

View File

@ -29,21 +29,21 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency>
<!-- sa-token整合redis (使用jdk默认序列化方式) -->
<!-- <dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency> -->
<!-- sa-token整合redis (使用jackson序列化方式) -->
<!-- <dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency> -->
<!-- 提供redis连接池 -->

View File

@ -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);
// }
}

View File

@ -11,6 +11,7 @@ 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;
@ -38,7 +39,8 @@ public class TestController {
System.out.println("登录成功");
System.out.println("当前是否登录:" + StpUtil.isLogin());
System.out.println("当前登录账号:" + StpUtil.getLoginId());
System.out.println("当前登录账号:" + StpUtil.getLoginIdAsInt()); // 获取登录id并转为int
// System.out.println("当前登录账号并转为int" + StpUtil.getLoginIdAsInt());
System.out.println("当前登录设备:" + StpUtil.getLoginDevice());
// System.out.println("当前token信息" + StpUtil.getTokenInfo());
return AjaxJson.getSuccess();
@ -151,13 +153,14 @@ public class TestController {
// 测试注解式鉴权 浏览器访问 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();
}
@ -192,10 +195,18 @@ public class TestController {
// 测试 浏览器访问 http://localhost:8081/test/test
@RequestMapping("test")
public AjaxJson test() {
StpUtil.getTokenSession().logout();
// 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();
}
}

View File

@ -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.8.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.8.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,7 +16,7 @@
---
## 😘 在线资料
## 在线资料
- [官网首页http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
@ -27,8 +27,8 @@
- [开源不易求鼓励点个star吧](https://github.com/click33/sa-token)
## sa-token是什么
**sa-token是一个JavaWeb轻量级权限认证框架其API调用非常简单有多简单呢以登录验证为例你只需要**
## sa-token是什么
sa-token是一个JavaWeb轻量级权限认证框架其API调用非常简单有多简单呢以登录验证为例你只需要
``` java
// 在登录时写入当前会话的账号id
@ -39,16 +39,16 @@ StpUtil.checkLogin();
```
**没有复杂的封装!不要任何的配置!只需这两行简单的调用,即可轻松完成系统登录鉴权!**
没有复杂的封装!不要任何的配置!只需这两行简单的调用,即可轻松完成系统登录鉴权!
## 🔥 框架设计思想
## 框架设计思想
与其它权限认证框架相比,`sa-token`尽力保证两点:
- 上手简单:能自动化的配置全部自动化,不让你费脑子
- 功能强大:能涵盖的功能全部涵盖,不让你用个框架还要自己给框架打各种补丁
**如果上面的示例能够证明`sa-token`的简单那么以下API则可以证明`sa-token`的强大**
如果上面的示例能够证明`sa-token`的简单那么以下API则可以证明`sa-token`的强大
``` java
StpUtil.setLoginId(10001); // 标记当前会话登录的账号id
StpUtil.getLoginId(); // 获取当前会话登录的账号id
@ -60,13 +60,15 @@ StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指定权
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众多请恕此处无法为您逐一展示更多示例请戳官方在线文档**
sa-token的API众多请恕此处无法为您逐一展示更多示例请戳官方在线文档
## 💦️️ 涵盖功能
## 涵盖功能
- **登录验证** —— 轻松登录鉴权,并提供五种细分场景值
- **权限验证** —— 拦截违规调用,不同角色不同授权
- **Session会话** —— 专业的数据缓存中心
@ -78,11 +80,12 @@ StpUtil.getTokenValueByLoginId(10001); // 获取账号id为10001的token令牌
- **注解式鉴权** —— 优雅的将鉴权与业务代码分离
- **花式token生成** —— 内置六种token风格还可自定义token生成策略
- **自动续签** —— 提供两种token过期策略灵活搭配使用还可自动续签
- **同端互斥登录** —— 像QQ一样手机电脑同时在线但是两个手机上互斥登录
- **组件自动注入** —— 零配置与Spring等框架集成
- **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流
## 🔨 贡献代码
## 贡献代码
sa-token欢迎大家贡献代码为框架添砖加瓦
1. 在github上fork一份到自己的仓库
2. clone自己的仓库到本地电脑
@ -91,7 +94,7 @@ sa-token欢迎大家贡献代码为框架添砖加瓦
5. 等待合并
## 🌱 建议贡献的地方
## 建议贡献的地方
- 修复源码现有bug或增加新的实用功能
- 完善在线文档,或者修复现有错误之处
- 更多demo示例比如SSM版搭建步骤
@ -99,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) ,欢迎你的加入

View File

@ -14,6 +14,7 @@
- [无Cookie模式(前后台分离)](/use/not-cookie)
- [模拟他人](/use/mock-person)
- [多账号验证](/use/many-account)
- [同端互斥登录](/use/mutex-login)
- [注解式鉴权](/use/at-check)
- [花式token](/use/token-style)
- [框架配置](/use/config)

View File

@ -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会话、踢人下线、集成Redis、前后台分离、模拟他人账号、多账号体系、注解式鉴权、花式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,7 @@
<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>
@ -37,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.8.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地址
@ -75,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>

View File

@ -1,5 +1,10 @@
# 更新日志
### 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
- 优化:优化源码注释

View File

@ -9,7 +9,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency>
```

View File

@ -18,7 +18,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency>
```

View File

@ -11,7 +11,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency>
```
优点兼容性好缺点session序列化后基本不可读对开发者来讲等同于乱码
@ -23,7 +23,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency>
```
优点session序列化后可读性强可灵活手动修改缺点兼容性稍差

View File

@ -7,8 +7,10 @@
- 所谓权限验证,验证的核心就是当前账号是否拥有一个权限码
- 有:就让你通过、没有:那么禁止访问
- 再往底了说,就是每个账号都会拥有一个权限码集合,我来验证这个集合中是否包括我需要检测的那个权限码
- 例如:当前账号拥有权限码集合:`[101, 102, "user-add", "user-get"]`,这时候我去验证权限码:`201`,则结果就是验证失败,禁止访问
- 所以现在问题的核心就是1、如何获取一个账号所拥有的的权限码集合2、本次操作要验证的权限码是哪个
- 例如:当前账号拥有权限码集合:`["user:add", "user:delete", "user:get"]`,这时候我去验证权限码:`"user:update"`,则结果就是验证失败,禁止访问
- 所以现在问题的核心就是:
1. 如何获取一个账号所拥有的的权限码集合
2. 本次操作要验证的权限码是哪个
## 获取当前账号权限码集合
因为每个项目的需求不同,其权限设计也千变万化,所以【获取当前账号权限码集合】这一操作不可能内置到框架中,
@ -34,8 +36,9 @@ 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");
@ -50,7 +53,8 @@ public class StpInterfaceImpl implements StpInterface {
*/
@Override
public List<String> getRoleList(Object loginId, String loginKey) {
List<String> list = new ArrayList<String>(); // 本list仅做模拟实际项目中要根据具体业务逻辑来查询角色
// 本list仅做模拟实际项目中要根据具体业务逻辑来查询角色
List<String> list = new ArrayList<String>();
list.add("admin");
list.add("super-admin");
return list;

View File

@ -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
```

View File

@ -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会话、踢人下线、集成Redis、前后台分离、模拟他人账号、多账号体系、注解式鉴权、花式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.8.0</small></h1>
<h1>sa-token<small>v1.9.0</small></h1>
<div class="sub-title">一个JavaWeb轻量级权限认证框架功能全面上手简单</div>
<!-- <p>0配置开箱即用低学习成本</p> -->
<p>登录验证、权限验证、Session会话、踢人下线、集成Redis、前后台分离、模拟他人账号、多账号体系、注解式鉴权、花式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 &nbsp;</span>
<a href="http://www.miitbeian.gov.cn/" target="_blank">鲁ICP备18046274号-2</a> &nbsp;
<a href="https://beian.miit.gov.cn/" target="_blank">鲁ICP备18046274号-2</a> &nbsp;
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>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-parent</artifactId>
<version>1.8.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.8.0</version>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -8,6 +8,7 @@ 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;
@ -58,25 +59,47 @@ public class SaCheckInterceptor implements HandlerInterceptor {
stpLogic.checkLogin();
}
// ----------- 验证角色
// 验证方法上的
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); // 有一个就行了
}
}
// 验证类上的
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); // 有一个就行了
}
}
// ----------- 验证权限
// 验证方法上的
SaCheckPermission scp = method.getMethodAnnotation(SaCheckPermission.class);
if(scp != null) {
String[] permissionCodeArray = scp.value();
String[] permissionArray = scp.value();
if(scp.mode() == SaMode.AND) {
stpLogic.checkPermissionAnd(permissionCodeArray); // 必须全部都有
stpLogic.checkPermissionAnd(permissionArray); // 必须全部都有
} else {
stpLogic.checkPermissionOr(permissionCodeArray); // 有一个就行了
stpLogic.checkPermissionOr(permissionArray); // 有一个就行了
}
}
// 验证类上的
scp = method.getBeanType().getAnnotation(SaCheckPermission.class);
if(scp != null) {
String[] permissionCodeArray = scp.value();
String[] permissionArray = scp.value();
if(scp.mode() == SaMode.AND) {
stpLogic.checkPermissionAnd(permissionCodeArray); // 必须全部都有
stpLogic.checkPermissionAnd(permissionArray); // 必须全部都有
} else {
stpLogic.checkPermissionOr(permissionCodeArray); // 有一个就行了
stpLogic.checkPermissionOr(permissionArray); // 有一个就行了
}
}