mirror of
https://gitee.com/dromara/sa-token.git
synced 2024-12-02 20:08:08 +08:00
commit
97a5fb2f40
31
README.md
31
README.md
@ -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) ,欢迎你的加入
|
||||
|
||||
|
||||
|
2
pom.xml
2
pom.xml
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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值
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 开源地址
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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连接池 -->
|
||||
|
@ -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);
|
||||
// }
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) ,欢迎你的加入
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
- 优化:优化源码注释
|
||||
|
@ -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>
|
||||
```
|
||||
|
||||
|
@ -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>
|
||||
```
|
||||
|
||||
|
@ -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序列化后可读性强,可灵活手动修改,缺点:兼容性稍差
|
||||
|
@ -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;
|
||||
|
39
sa-token-doc/doc/use/mutex-login.md
Normal file
39
sa-token-doc/doc/use/mutex-login.md
Normal 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
|
||||
```
|
||||
|
||||
|
@ -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 </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.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>
|
||||
|
@ -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); // 有一个就行了
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user