新增Sa-Id模块,解决微服务内部调用鉴权问题

This commit is contained in:
click33
2021-07-24 01:10:46 +08:00
parent bffdd0f2e1
commit 64beb7a18a
12 changed files with 767 additions and 16 deletions

View File

@@ -18,7 +18,7 @@ public class SaTokenConfig implements Serializable {
private String tokenName = "satoken";
/** token的长久有效期(单位:秒) 默认30天, -1代表永久 */
private long timeout = 30 * 24 * 60 * 60;
private long timeout = 60 * 60 * 24 * 30;
/**
* token临时有效期 [指定时间内无操作就视为token过期] (单位: 秒), 默认-1 代表不限制
@@ -70,6 +70,12 @@ public class SaTokenConfig implements Serializable {
*/
private String jwtSecretKey;
/**
* Id-Token的有效期 (单位: 秒)
*/
private long idTokenTimeout = 60 * 60 * 24;
/**
* SSO单点登录配置对象
*/
@@ -352,6 +358,22 @@ public class SaTokenConfig implements Serializable {
return this;
}
/**
* @return Id-Token的有效期 (单位: 秒)
*/
public long getIdTokenTimeout() {
return idTokenTimeout;
}
/**
* @param idTokenTimeout Id-Token的有效期 (单位: 秒)
* @return 对象自身
*/
public SaTokenConfig setIdTokenTimeout(long idTokenTimeout) {
this.idTokenTimeout = idTokenTimeout;
return this;
}
/**
* @return SSO单点登录配置对象
*/
@@ -359,7 +381,6 @@ public class SaTokenConfig implements Serializable {
return sso;
}
/**
* @param sso SSO单点登录配置对象
*/
@@ -367,19 +388,15 @@ public class SaTokenConfig implements Serializable {
this.sso = sso;
}
/**
* toString()
*/
@Override
public String toString() {
return "SaTokenConfig [tokenName=" + tokenName + ", timeout=" + timeout + ", activityTimeout=" + activityTimeout
+ ", isConcurrent=" + isConcurrent + ", isShare=" + isShare + ", isReadBody="
+ isReadBody + ", isReadHead=" + isReadHead + ", isReadCookie=" + isReadCookie + ", tokenStyle="
+ tokenStyle + ", dataRefreshPeriod=" + dataRefreshPeriod + ", tokenSessionCheckLogin="
+ tokenSessionCheckLogin + ", autoRenew=" + autoRenew + ", cookieDomain=" + cookieDomain
+ ", tokenPrefix=" + tokenPrefix + ", isPrint=" + isPrint + ", isLog=" + isLog + ", jwtSecretKey="
+ jwtSecretKey + ", sso=" + sso + "]";
+ ", isConcurrent=" + isConcurrent + ", isShare=" + isShare + ", isReadBody=" + isReadBody
+ ", isReadHead=" + isReadHead + ", isReadCookie=" + isReadCookie + ", tokenStyle=" + tokenStyle
+ ", dataRefreshPeriod=" + dataRefreshPeriod + ", tokenSessionCheckLogin=" + tokenSessionCheckLogin
+ ", autoRenew=" + autoRenew + ", cookieDomain=" + cookieDomain + ", tokenPrefix=" + tokenPrefix
+ ", isPrint=" + isPrint + ", isLog=" + isLog + ", jwtSecretKey=" + jwtSecretKey + ", idTokenTimeout="
+ idTokenTimeout + ", sso=" + sso + "]";
}

View File

@@ -0,0 +1,22 @@
package cn.dev33.satoken.exception;
/**
* 一个异常:代表提供的 Id-Token 无效
*
* @author kong
*/
public class IdTokenInvalidException extends SaTokenException {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 6806129545290130144L;
/**
* 一个异常:代表提供的 Id-Token 无效
*/
public IdTokenInvalidException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,172 @@
package cn.dev33.satoken.id;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.IdTokenInvalidException;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token-Id 身份凭证模块
* <p> 身份凭证的获取与校验,可用于微服务内部调用鉴权
* @author kong
*
*/
public class SaIdTemplate {
/**
* 在 Request 上储存 Id-Token 时建议使用的key
*/
public static final String ID_TOKEN = "SA_ID_TOKEN";
// -------------------- 获取 & 校验
/**
* 获取当前Id-Token, 如果不存在,则立即创建并返回
* @return 当前token
*/
public String getToken() {
String currentToken = getTokenNh();
if(SaFoxUtil.isEmpty(currentToken)) {
// 注意这里的自刷新不能做到高并发可用
currentToken = refreshToken();
}
return currentToken;
}
/**
* 判断一个Id-Token是否有效
* @param token 要验证的token
* @return 这个token是否有效
*/
public boolean isValid(String token) {
// 1、 如果传入的token未空立即返回false
if(SaFoxUtil.isEmpty(token)) {
return false;
}
// 2、 验证当前 Id-Token 及 Past-Id-Token
return token.equals(getToken()) || token.equals(getPastTokenNh());
}
/**
* 校验一个Id-Token是否有效 (如果无效则抛出异常)
* @param token 要验证的token
*/
public void checkToken(String token) {
if(isValid(token) == false) {
token = (token == null ? "" : token);
throw new IdTokenInvalidException("无效Id-Token" + token);
}
}
/**
* 校验当前Request提供的Id-Token是否有效 (如果无效则抛出异常)
*/
public void checkCurrentRequestToken() {
checkToken(SaHolder.getRequest().getHeader(ID_TOKEN));
}
/**
* 刷新一次Id-Token (注意集群环境中不要多个服务重复调用)
* @return 新Token
*/
public String refreshToken() {
// 1. 先将当前 Id-Token 写入到 Past-Id-Token 中
String idToken = getTokenNh();
if(SaFoxUtil.isEmpty(idToken) == false) {
savePastToken(idToken, getTokenTimeout());
}
// 2. 再刷新当前Id-Token
String newIdToken = createToken();
saveToken(newIdToken);
// 3. 返回新的 Id-Token
return newIdToken;
}
// ------------------------------ 保存Token
/**
* 保存Id-Token
* @param token
*/
public void saveToken(String token) {
if(SaFoxUtil.isEmpty(token)) {
return;
}
SaManager.getSaTokenDao().set(splicingTokenSaveKey(), token, SaManager.getConfig().getIdTokenTimeout());
}
/**
* 保存Past-Id-Token
* @param token token
* @param timeout 有效期(单位:秒)
*/
public void savePastToken(String token, long timeout){
if(SaFoxUtil.isEmpty(token)) {
return;
}
SaManager.getSaTokenDao().set(splicingPastTokenSaveKey(), token, timeout);
}
// -------------------- 获取Token
/**
* 获取Id-Token不做任何处理
* @return token
*/
public String getTokenNh() {
return SaManager.getSaTokenDao().get(splicingTokenSaveKey());
}
/**
* 获取Past-Id-Token不做任何处理
* @return token
*/
public String getPastTokenNh() {
return SaManager.getSaTokenDao().get(splicingPastTokenSaveKey());
}
/**
* 获取Id-Token的剩余有效期 (单位:秒)
* @return token
*/
public long getTokenTimeout() {
return SaManager.getSaTokenDao().getTimeout(splicingTokenSaveKey());
}
// -------------------- 创建Token
/**
* 创建一个Id-Token
* @return Token
*/
public String createToken() {
return SaFoxUtil.getRandomString(60);
}
// -------------------- 拼接key
/**
* 拼接keyId-Token的存储key
* @return key
*/
public String splicingTokenSaveKey() {
return SaManager.getConfig().getTokenName() + ":var:id-token";
}
/**
* 拼接keyId-Token的存储key
* @return key
*/
public String splicingPastTokenSaveKey() {
return SaManager.getConfig().getTokenName() + ":var:past-id-token";
}
}

View File

@@ -0,0 +1,81 @@
package cn.dev33.satoken.id;
/**
* Sa-Token-Id 身份凭证模块-工具类
* @author kong
*
*/
public class SaIdUtil {
/**
* 在 Request 上储存 Id-Token 时建议使用的key
*/
public static final String ID_TOKEN = SaIdTemplate.ID_TOKEN;
/**
* 底层 SaIdTemplate 对象
*/
public static SaIdTemplate saIdTemplate = new SaIdTemplate();
// -------------------- 获取 & 校验
/**
* 获取当前Id-Token, 如果不存在,则立即创建并返回
* @return 当前token
*/
public static String getToken() {
return saIdTemplate.getToken();
}
/**
* 判断一个Id-Token是否有效
* @param token 要验证的token
* @return 这个token是否有效
*/
public static boolean isValid(String token) {
return saIdTemplate.isValid(token);
}
/**
* 校验一个Id-Token是否有效 (如果无效则抛出异常)
* @param token 要验证的token
*/
public static void checkToken(String token) {
saIdTemplate.checkToken(token);
}
/**
* 校验当前Request提供的Id-Token是否有效 (如果无效则抛出异常)
*/
public static void checkCurrentRequestToken() {
saIdTemplate.checkCurrentRequestToken();
}
/**
* 刷新一次Id-Token (注意集群环境中不要多个服务重复调用)
* @return 新Token
*/
public static String refreshToken() {
return saIdTemplate.refreshToken();
}
// -------------------- 获取Token
/**
* 获取Id-Token不做任何处理
* @return token
*/
public static String getTokenNh() {
return saIdTemplate.getTokenNh();
}
/**
* 获取Past-Id-Token不做任何处理
* @return token
*/
public static String getPastTokenNh() {
return saIdTemplate.getPastTokenNh();
}
}

View File

@@ -13,7 +13,7 @@ import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token-SSO 单点登录接口
* Sa-Token-SSO 单点登录模块
* @author kong
*
*/