mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-04-05 17:37:53 +08:00
重构:API 接口签名所有方法均迁移至 core 核心模块。
This commit is contained in:
parent
aa2663e3f5
commit
ac09cced2b
@ -1,8 +1,5 @@
|
||||
package cn.dev33.satoken;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.config.SaTokenConfigFactory;
|
||||
import cn.dev33.satoken.context.SaTokenContext;
|
||||
@ -19,7 +16,6 @@ import cn.dev33.satoken.log.SaLog;
|
||||
import cn.dev33.satoken.log.SaLogForConsole;
|
||||
import cn.dev33.satoken.same.SaSameTemplate;
|
||||
import cn.dev33.satoken.sign.SaSignTemplate;
|
||||
import cn.dev33.satoken.sign.SaSignTemplateDefaultImpl;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
@ -28,6 +24,9 @@ import cn.dev33.satoken.temp.SaTempDefaultImpl;
|
||||
import cn.dev33.satoken.temp.SaTempInterface;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 管理 Sa-Token 所有全局组件
|
||||
* @author kong
|
||||
@ -209,7 +208,7 @@ public class SaManager {
|
||||
if (saSignTemplate == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saSignTemplate == null) {
|
||||
SaManager.saSignTemplate = new SaSignTemplateDefaultImpl();
|
||||
SaManager.saSignTemplate = new SaSignTemplate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,111 @@
|
||||
package cn.dev33.satoken.config;
|
||||
|
||||
/**
|
||||
* Sa-Token API 接口签名/验签 相关配置类
|
||||
*
|
||||
* @author click33
|
||||
* @since 2023/5/2
|
||||
*/
|
||||
public class SaSignConfig {
|
||||
|
||||
/**
|
||||
* API 调用签名秘钥
|
||||
*/
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距,默认15分钟
|
||||
*/
|
||||
private long timestampDisparity = 1000 * 60 * 15;
|
||||
|
||||
/**
|
||||
* 是否校验 nonce 随机字符串
|
||||
*/
|
||||
private Boolean isCheckNonce = true;
|
||||
|
||||
|
||||
/**
|
||||
* 获取 API 调用签名秘钥
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public String getSecretKey() {
|
||||
return this.secretKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 API 调用签名秘钥
|
||||
*
|
||||
* @param secretKey /
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSignConfig setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距,默认15分钟
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public long getTimestampDisparity() {
|
||||
return this.timestampDisparity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距,默认15分钟
|
||||
*
|
||||
* @param timestampDisparity /
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSignConfig setTimestampDisparity(long timestampDisparity) {
|
||||
this.timestampDisparity = timestampDisparity;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 是否校验 nonce 随机字符串
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public Boolean getIsCheckNonce() {
|
||||
return this.isCheckNonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 是否校验 nonce 随机字符串
|
||||
*
|
||||
* @param isCheckNonce /
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSignConfig setIsCheckNonce(Boolean isCheckNonce) {
|
||||
this.isCheckNonce = isCheckNonce;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算保存 nonce 时应该使用的 ttl,单位:秒
|
||||
* @return /
|
||||
*/
|
||||
public long getSaveNonceExpire() {
|
||||
// 如果 timestampDisparity >= 0,则 nonceTtl 的值等于 timestampDisparity 的值,单位转秒
|
||||
if(timestampDisparity >= 0) {
|
||||
return timestampDisparity / 1000;
|
||||
}
|
||||
// 否则,nonceTtl 的值为 24 小时
|
||||
else {
|
||||
return 60 * 60 * 24;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaSignConfig ["
|
||||
+ "secretKey=" + secretKey
|
||||
+ ", timestampDisparity=" + timestampDisparity
|
||||
+ ", isCheckNonce=" + isCheckNonce
|
||||
+ "]";
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package cn.dev33.satoken.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Sa-Token 配置类 Model
|
||||
* <p>
|
||||
@ -109,7 +109,12 @@ public class SaTokenConfig implements Serializable {
|
||||
* Cookie配置对象
|
||||
*/
|
||||
public SaCookieConfig cookie = new SaCookieConfig();
|
||||
|
||||
|
||||
/**
|
||||
* API 签名配置对象
|
||||
*/
|
||||
public SaSignConfig sign = new SaSignConfig();
|
||||
|
||||
|
||||
/**
|
||||
* @return token名称 (同时也是cookie名称)
|
||||
@ -532,7 +537,23 @@ public class SaTokenConfig implements Serializable {
|
||||
this.cookie = cookie;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return API 签名全局配置对象
|
||||
*/
|
||||
public SaSignConfig getSign() {
|
||||
return sign;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sign API 签名全局配置对象
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenConfig setSign(SaSignConfig sign) {
|
||||
this.sign = sign;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaTokenConfig ["
|
||||
@ -561,7 +582,8 @@ public class SaTokenConfig implements Serializable {
|
||||
+ ", currDomain=" + currDomain
|
||||
+ ", sameTokenTimeout=" + sameTokenTimeout
|
||||
+ ", checkSameToken=" + checkSameToken
|
||||
+ ", cookie=" + cookie
|
||||
+ ", cookie=" + cookie
|
||||
+ ", sign=" + sign
|
||||
+ "]";
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,48 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 API 参数签名校验失败
|
||||
*
|
||||
* @author kong
|
||||
* @since 2023-5-3
|
||||
*/
|
||||
public class SaSignException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130144L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 API 参数签名校验失败
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public SaSignException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果flag==true,则抛出message异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message) {
|
||||
if(flag) {
|
||||
throw new SaSignException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 value isEmpty,则抛出 message 异常
|
||||
* @param value 值
|
||||
* @param message 异常信息
|
||||
*/
|
||||
public static void throwByNull(Object value, String message) {
|
||||
if(SaFoxUtil.isEmpty(value)) {
|
||||
throw new SaSignException(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
package cn.dev33.satoken.sign;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaSignConfig;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.exception.SaSignException;
|
||||
import cn.dev33.satoken.secure.SaSecureUtil;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
@ -9,19 +12,74 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* 参数签名算法
|
||||
* API 参数签名算法
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-4-27
|
||||
*/
|
||||
public interface SaSignTemplate {
|
||||
public class SaSignTemplate {
|
||||
|
||||
// ----------- 签名配置
|
||||
|
||||
SaSignConfig signConfig;
|
||||
|
||||
/**
|
||||
* 获取:API 签名配置
|
||||
* @return /
|
||||
*/
|
||||
public SaSignConfig getSignConfig() {
|
||||
return signConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取:API 签名配置:
|
||||
* 1. 如果用户自定义了 signConfig ,则使用用户自定义的。
|
||||
* 2. 否则使用全局默认配置。
|
||||
* @return /
|
||||
*/
|
||||
public SaSignConfig getSignConfigOrGlobal() {
|
||||
// 如果用户自定义了 signConfig ,则使用用户自定义的
|
||||
if(signConfig != null) {
|
||||
return signConfig;
|
||||
}
|
||||
// 否则使用全局默认配置
|
||||
return SaManager.getConfig().getSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取:API 签名配置的秘钥
|
||||
* @return /
|
||||
*/
|
||||
public String getSecretKey() {
|
||||
return getSignConfigOrGlobal().getSecretKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置:API 签名配置
|
||||
* @param signConfig /
|
||||
*/
|
||||
public SaSignTemplate setSignConfig(SaSignConfig signConfig) {
|
||||
this.signConfig = signConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// ----------- 自定义使用的参数名称 (不声明final,允许开发者自定义修改)
|
||||
|
||||
public static String key = "key";
|
||||
public static String timestamp = "timestamp";
|
||||
public static String nonce = "nonce";
|
||||
public static String sign = "sign";
|
||||
|
||||
|
||||
// ----------- 拼接参数
|
||||
|
||||
/**
|
||||
* 将所有参数连接成一个字符串(不排序),形如:b=28a=18c=3
|
||||
* @param paramsMap 参数列表
|
||||
* @return 拼接出的参数字符串
|
||||
*/
|
||||
public default String joinParams(Map<String, ?> paramsMap) {
|
||||
public String joinParams(Map<String, ?> paramsMap) {
|
||||
|
||||
// 按照 k1=v1&k2=v2&k3=v3 排列
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@ -46,7 +104,7 @@ public interface SaSignTemplate {
|
||||
* @param paramsMap 参数列表
|
||||
* @return 拼接出的参数字符串
|
||||
*/
|
||||
public default String joinParamsDictSort(Map<String, ?> paramsMap) {
|
||||
public String joinParamsDictSort(Map<String, ?> paramsMap) {
|
||||
// 保证字段按照字典顺序排列
|
||||
if( ! (paramsMap instanceof TreeMap) ) {
|
||||
paramsMap = new TreeMap<>(paramsMap);
|
||||
@ -56,62 +114,40 @@ public interface SaSignTemplate {
|
||||
return joinParams(paramsMap);
|
||||
}
|
||||
|
||||
|
||||
// ----------- 创建签名
|
||||
|
||||
/**
|
||||
* 创建签名:md5(paramsStr + keyStr)
|
||||
* @param paramsMap 参数列表
|
||||
* @param key 秘钥
|
||||
* @param paramsMap 参数列表
|
||||
* @return 签名
|
||||
*/
|
||||
public default String createSign(Map<String, ?> paramsMap, String key) {
|
||||
SaTokenException.throwByNull(key, "参与参数签名的秘钥不可为空", SaErrorCode.CODE_12201);
|
||||
public String createSign(Map<String, ?> paramsMap) {
|
||||
String secretKey = getSecretKey();
|
||||
SaSignException.throwByNull(secretKey, "参与参数签名的秘钥不可为空", SaErrorCode.CODE_12201);
|
||||
|
||||
// 如果调用者不小心传入了 sign 参数,则此处需要将 sign 参数排除在外
|
||||
// 为了保证不影响原有的 paramsMap,此处需要再复制一份
|
||||
if(paramsMap.containsKey("sign")) {
|
||||
if(paramsMap.containsKey(sign)) {
|
||||
// 为了保证不影响原有的 paramsMap,此处需要再复制一份
|
||||
paramsMap = new TreeMap<>(paramsMap);
|
||||
paramsMap.remove("sign");
|
||||
paramsMap.remove(sign);
|
||||
}
|
||||
|
||||
// 计算签名
|
||||
String paramsStr = joinParamsDictSort(paramsMap);
|
||||
String fullStr = paramsStr + "&key=" + key;
|
||||
String fullStr = paramsStr + "&" + key + "=" + secretKey;
|
||||
return SaSecureUtil.md5(fullStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:给定的参数 + 秘钥 生成的签名是否为有效签名
|
||||
* @param paramsMap 参数列表
|
||||
* @param key 秘钥
|
||||
* @param sign 待验证的签名
|
||||
* @return 签名是否有效
|
||||
*/
|
||||
public default boolean isValidSign(Map<String, ?> paramsMap, String key, String sign) {
|
||||
String theSign = createSign(paramsMap, key);
|
||||
return theSign.equals(sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:给定的参数 + 秘钥 生成的签名是否为有效签名,如果签名无效则抛出异常
|
||||
* @param paramsMap 参数列表
|
||||
* @param key 秘钥
|
||||
* @param sign 待验证的签名
|
||||
*/
|
||||
public default void checkSign(Map<String, ?> paramsMap, String key, String sign) {
|
||||
if( ! isValidSign(paramsMap, key, sign) ) {
|
||||
throw new SaTokenException("无效签名:" + sign).setCode(SaErrorCode.CODE_12202);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数
|
||||
* @param paramsMap 参数列表
|
||||
* @param key 秘钥
|
||||
* @param paramsMap 参数列表
|
||||
* @return 加工后的参数列表
|
||||
*/
|
||||
public default Map<String, Object> addSignParams(Map<String, Object> paramsMap, String key) {
|
||||
paramsMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
||||
paramsMap.put("nonce", SaFoxUtil.getRandomString(32));
|
||||
paramsMap.put("sign", createSign(paramsMap, key));
|
||||
public Map<String, Object> addSignParams(Map<String, Object> paramsMap) {
|
||||
paramsMap.put(timestamp, String.valueOf(System.currentTimeMillis()));
|
||||
paramsMap.put(nonce, SaFoxUtil.getRandomString(32));
|
||||
paramsMap.put(sign, createSign(paramsMap));
|
||||
return paramsMap;
|
||||
}
|
||||
|
||||
@ -119,24 +155,26 @@ public interface SaSignTemplate {
|
||||
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数,并转换为参数字符串,形如:
|
||||
* <code>data=xxx8nonce=xxx8timestamp=xxx8sign=xxx</code>
|
||||
* @param paramsMap 参数列表
|
||||
* @param key 秘钥
|
||||
* @return 加工后的参数列表 转化为的参数字符串
|
||||
*/
|
||||
public default String addSignParamsAndToString(Map<String, Object> paramsMap, String key) {
|
||||
public String addSignParamsAndJoin(Map<String, Object> paramsMap) {
|
||||
// 追加参数
|
||||
paramsMap = addSignParams(paramsMap, key);
|
||||
paramsMap = addSignParams(paramsMap);
|
||||
|
||||
// .
|
||||
// 拼接参数
|
||||
return joinParams(paramsMap);
|
||||
}
|
||||
|
||||
|
||||
// ----------- 校验签名
|
||||
|
||||
/**
|
||||
* 判断:指定时间戳与当前时间戳的差距是否在允许的范围内
|
||||
* @param timestamp 待校验的时间戳
|
||||
* @param allowDisparity 允许的最大时间差(单位:ms),-1 代表不限制
|
||||
* @return 是否在允许的范围内
|
||||
*/
|
||||
public default boolean isValidTimestamp(long timestamp, long allowDisparity) {
|
||||
public boolean isValidTimestamp(long timestamp) {
|
||||
long allowDisparity = getSignConfigOrGlobal().getTimestampDisparity();
|
||||
long disparity = Math.abs(System.currentTimeMillis() - timestamp);
|
||||
return allowDisparity == -1 || disparity <= allowDisparity;
|
||||
}
|
||||
@ -144,29 +182,142 @@ public interface SaSignTemplate {
|
||||
/**
|
||||
* 校验:指定时间戳与当前时间戳的差距是否在允许的范围内,如果超出则抛出异常
|
||||
* @param timestamp 待校验的时间戳
|
||||
* @param allowDisparity 允许的最大时间差(单位:ms),-1 代表不限制
|
||||
*/
|
||||
public default void checkTimestamp(long timestamp, long allowDisparity) {
|
||||
if( ! isValidTimestamp(timestamp, allowDisparity) ) {
|
||||
throw new SaTokenException("timestamp 超出允许的范围:" + timestamp).setCode(SaErrorCode.CODE_12203);
|
||||
public void checkTimestamp(long timestamp) {
|
||||
if( ! isValidTimestamp(timestamp) ) {
|
||||
throw new SaSignException("timestamp 超出允许的范围:" + timestamp).setCode(SaErrorCode.CODE_12203);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ 以下为兼容旧版本的方法 ------------------
|
||||
/**
|
||||
* 判断:随机字符串 nonce 是否有效。
|
||||
* 注意:同一 nonce 可以被多次判断有效,不会被缓存
|
||||
* @param nonce 待判断的随机字符串
|
||||
* @return 是否有效
|
||||
*/
|
||||
public boolean isValidNonce(String nonce) {
|
||||
// 为空代表无效
|
||||
if(SaFoxUtil.isEmpty(nonce)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 校验此 nonce 是否已被使用过
|
||||
String key = splicingNonceSaveKey(nonce);
|
||||
return SaManager.getSaTokenDao().get(key) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请更换为 addSignParamsAndToString
|
||||
* @param paramsMap 参数列表
|
||||
* @param key 秘钥
|
||||
* @return 加工后的参数列表 转化为的参数字符串
|
||||
* 校验:随机字符串 nonce 是否有效,如果无效则抛出异常。
|
||||
* 注意:同一 nonce 只可以被校验通过一次,校验后将保存在缓存中,再次校验将无法通过
|
||||
* @param nonce 待校验的随机字符串
|
||||
*/
|
||||
@Deprecated
|
||||
public default String addSignParamsToString(Map<String, Object> paramsMap, String key) {
|
||||
// 追加参数
|
||||
paramsMap = addSignParams(paramsMap, key);
|
||||
public void checkNonce(String nonce) {
|
||||
// 为空代表无效
|
||||
if(SaFoxUtil.isEmpty(nonce)) {
|
||||
throw new SaSignException("nonce 为空,无效");
|
||||
}
|
||||
|
||||
// .
|
||||
return joinParams(paramsMap);
|
||||
// 校验此 nonce 是否已被使用过
|
||||
String key = splicingNonceSaveKey(nonce);
|
||||
if(SaManager.getSaTokenDao().get(key) != null) {
|
||||
throw new SaSignException("此 nonce 已被使用过,不可重复使用:" + nonce);
|
||||
}
|
||||
|
||||
// 校验通过后,将此 nonce 保存在缓存中,保证下次校验无法通过
|
||||
SaManager.getSaTokenDao().set(key, nonce, getSignConfigOrGlobal().getSaveNonceExpire());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:给定的参数 + 秘钥 生成的签名是否为有效签名
|
||||
* @param paramsMap 参数列表
|
||||
* @param sign 待验证的签名
|
||||
* @return 签名是否有效
|
||||
*/
|
||||
public boolean isValidSign(Map<String, ?> paramsMap, String sign) {
|
||||
String theSign = createSign(paramsMap);
|
||||
return theSign.equals(sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:给定的参数 + 秘钥 生成的签名是否为有效签名,如果签名无效则抛出异常
|
||||
* @param paramsMap 参数列表
|
||||
* @param sign 待验证的签名
|
||||
*/
|
||||
public void checkSign(Map<String, ?> paramsMap, String sign) {
|
||||
if( ! isValidSign(paramsMap, sign) ) {
|
||||
throw new SaSignException("无效签名:" + sign).setCode(SaErrorCode.CODE_12202);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:参数列表中的 nonce、timestamp、sign 是否均为合法的
|
||||
* @param paramMap 待校验的请求参数集合
|
||||
* @return 是否合法
|
||||
*/
|
||||
public boolean isValidParamMap(Map<String, String> paramMap) {
|
||||
// 获取必须的三个参数
|
||||
String timestampValue = paramMap.get(timestamp);
|
||||
String nonceValue = paramMap.get(nonce);
|
||||
String signValue = paramMap.get(sign);
|
||||
|
||||
// 三个参数必须全部非空
|
||||
SaSignException.throwByNull(timestampValue, "缺少 timestamp 字段");
|
||||
SaSignException.throwByNull(nonceValue, "缺少 nonce 字段");
|
||||
SaSignException.throwByNull(signValue, "缺少 sign 字段");
|
||||
|
||||
// 三个值的校验必须全部通过
|
||||
return isValidTimestamp(Long.parseLong(timestampValue))
|
||||
&& (getSignConfigOrGlobal().getIsCheckNonce() ? isValidNonce(nonceValue) : true)
|
||||
&& isValidSign(paramMap, signValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:参数列表中的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
|
||||
* @param paramMap 待校验的请求参数集合
|
||||
*/
|
||||
public void checkParamMap(Map<String, String> paramMap) {
|
||||
// 获取必须的三个参数
|
||||
String timestampValue = paramMap.get(timestamp);
|
||||
String nonceValue = paramMap.get(nonce);
|
||||
String signValue = paramMap.get(sign);
|
||||
|
||||
// 依次校验三个参数
|
||||
checkTimestamp(Long.parseLong(timestampValue));
|
||||
if(getSignConfigOrGlobal().getIsCheckNonce()) {
|
||||
checkNonce(nonceValue);
|
||||
}
|
||||
checkSign(paramMap, signValue);
|
||||
|
||||
// 通过 √
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:一个请求中的 nonce、timestamp、sign 是否均为合法的
|
||||
* @param request 待校验的请求对象
|
||||
* @return 是否合法
|
||||
*/
|
||||
public boolean isValidRequest(SaRequest request) {
|
||||
return isValidParamMap(request.getParamMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:一个请求的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
|
||||
* @param request 待校验的请求对象
|
||||
*/
|
||||
public void checkRequest(SaRequest request) {
|
||||
checkParamMap(request.getParamMap());
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 返回相应key -------------------
|
||||
|
||||
/**
|
||||
* 拼接key:存储 nonce 时使用的 key
|
||||
* @param nonce nonce 值
|
||||
* @return key
|
||||
*/
|
||||
public String splicingNonceSaveKey(String nonce) {
|
||||
return SaManager.getConfig().getTokenName() + ":sign:nonce:" + nonce;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
package cn.dev33.satoken.sign;
|
||||
|
||||
/**
|
||||
* 参数签名算法 [默认实现类]
|
||||
*
|
||||
* @author kong
|
||||
* @since: 2022-4-27
|
||||
*/
|
||||
public class SaSignTemplateDefaultImpl implements SaSignTemplate {
|
||||
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
package cn.dev33.satoken.sign;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* API 参数签名算法 - 工具类
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-4-27
|
||||
*/
|
||||
public class SaSignUtil {
|
||||
|
||||
// ----------- 拼接参数
|
||||
|
||||
/**
|
||||
* 将所有参数连接成一个字符串(不排序),形如:b=28a=18c=3
|
||||
* @param paramsMap 参数列表
|
||||
* @return 拼接出的参数字符串
|
||||
*/
|
||||
public static String joinParams(Map<String, ?> paramsMap) {
|
||||
return SaManager.getSaSignTemplate().joinParams(paramsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有参数按照字典顺序连接成一个字符串,形如:a=18b=28c=3
|
||||
* @param paramsMap 参数列表
|
||||
* @return 拼接出的参数字符串
|
||||
*/
|
||||
public static String joinParamsDictSort(Map<String, ?> paramsMap) {
|
||||
return SaManager.getSaSignTemplate().joinParamsDictSort(paramsMap);
|
||||
}
|
||||
|
||||
|
||||
// ----------- 创建签名
|
||||
|
||||
/**
|
||||
* 创建签名:md5(paramsStr + keyStr)
|
||||
* @param paramsMap 参数列表
|
||||
* @return 签名
|
||||
*/
|
||||
public static String createSign(Map<String, ?> paramsMap) {
|
||||
return SaManager.getSaSignTemplate().createSign(paramsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数
|
||||
* @param paramsMap 参数列表
|
||||
* @return 加工后的参数列表
|
||||
*/
|
||||
public static Map<String, Object> addSignParams(Map<String, Object> paramsMap) {
|
||||
return SaManager.getSaSignTemplate().addSignParams(paramsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数,并转换为参数字符串,形如:
|
||||
* <code>data=xxx8nonce=xxx8timestamp=xxx8sign=xxx</code>
|
||||
* @param paramsMap 参数列表
|
||||
* @return 加工后的参数列表 转化为的参数字符串
|
||||
*/
|
||||
public static String addSignParamsAndJoin(Map<String, Object> paramsMap) {
|
||||
return SaManager.getSaSignTemplate().addSignParamsAndJoin(paramsMap);
|
||||
}
|
||||
|
||||
|
||||
// ----------- 校验签名
|
||||
|
||||
/**
|
||||
* 判断:指定时间戳与当前时间戳的差距是否在允许的范围内
|
||||
* @param timestamp 待校验的时间戳
|
||||
* @return 是否在允许的范围内
|
||||
*/
|
||||
public static boolean isValidTimestamp(long timestamp) {
|
||||
return SaManager.getSaSignTemplate().isValidTimestamp(timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:指定时间戳与当前时间戳的差距是否在允许的范围内,如果超出则抛出异常
|
||||
* @param timestamp 待校验的时间戳
|
||||
*/
|
||||
public static void checkTimestamp(long timestamp) {
|
||||
SaManager.getSaSignTemplate().checkTimestamp(timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:随机字符串 nonce 是否有效。
|
||||
* 注意:同一 nonce 可以被多次判断有效,不会被缓存
|
||||
* @param nonce 待判断的随机字符串
|
||||
* @return 是否有效
|
||||
*/
|
||||
public static boolean isValidNonce(String nonce) {
|
||||
return SaManager.getSaSignTemplate().isValidNonce(nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:随机字符串 nonce 是否有效,如果无效则抛出异常。
|
||||
* 注意:同一 nonce 只可以被校验通过一次,校验后将保存在缓存中,再次校验将无法通过
|
||||
* @param nonce 待校验的随机字符串
|
||||
*/
|
||||
public static void checkNonce(String nonce) {
|
||||
SaManager.getSaSignTemplate().checkNonce(nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:给定的参数 + 秘钥 生成的签名是否为有效签名
|
||||
* @param paramsMap 参数列表
|
||||
* @param sign 待验证的签名
|
||||
* @return 签名是否有效
|
||||
*/
|
||||
public static boolean isValidSign(Map<String, ?> paramsMap, String sign) {
|
||||
return SaManager.getSaSignTemplate().isValidSign(paramsMap, sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:给定的参数 + 秘钥 生成的签名是否为有效签名,如果签名无效则抛出异常
|
||||
* @param paramsMap 参数列表
|
||||
* @param sign 待验证的签名
|
||||
*/
|
||||
public static void checkSign(Map<String, ?> paramsMap, String sign) {
|
||||
SaManager.getSaSignTemplate().checkSign(paramsMap, sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:参数列表中的 nonce、timestamp、sign 是否均为合法的
|
||||
* @param paramMap 待校验的请求参数集合
|
||||
* @return 是否合法
|
||||
*/
|
||||
public static boolean isValidParamMap(Map<String, String> paramMap) {
|
||||
return SaManager.getSaSignTemplate().isValidParamMap(paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:参数列表中的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
|
||||
* @param paramMap 待校验的请求参数集合
|
||||
*/
|
||||
public static void checkParamMap(Map<String, String> paramMap) {
|
||||
SaManager.getSaSignTemplate().checkParamMap(paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:一个请求中的 nonce、timestamp、sign 是否均为合法的
|
||||
* @param request 待校验的请求对象
|
||||
* @return 是否合法
|
||||
*/
|
||||
public static boolean isValidRequest(SaRequest request) {
|
||||
return SaManager.getSaSignTemplate().isValidRequest(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:一个请求的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
|
||||
* @param request 待校验的请求对象
|
||||
*/
|
||||
public static void checkRequest(SaRequest request) {
|
||||
SaManager.getSaSignTemplate().checkRequest(request);
|
||||
}
|
||||
|
||||
}
|
@ -2,8 +2,8 @@ package com.pj.sso;
|
||||
|
||||
import cn.dev33.satoken.config.SaSsoConfig;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.sign.SaSignUtil;
|
||||
import cn.dev33.satoken.sso.SaSsoProcessor;
|
||||
import cn.dev33.satoken.sso.SaSsoUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.dtflys.forest.Forest;
|
||||
@ -66,13 +66,13 @@ public class SsoServerController {
|
||||
|
||||
// 示例:获取数据接口(用于在模式三下,为 client 端开放拉取数据的接口)
|
||||
@RequestMapping("/sso/getData")
|
||||
public Object userinfo(String apiType, String loginId) {
|
||||
public Object getData(String apiType, String loginId) {
|
||||
System.out.println("---------------- 获取数据 ----------------");
|
||||
System.out.println("apiType=" + apiType);
|
||||
System.out.println("loginId=" + loginId);
|
||||
|
||||
// 校验签名:只有拥有正确秘钥发起的请求才能通过校验
|
||||
SaSsoUtil.checkSign(SaHolder.getRequest());
|
||||
SaSignUtil.checkRequest(SaHolder.getRequest());
|
||||
|
||||
// 自定义返回结果(模拟)
|
||||
return SaResult.ok()
|
||||
|
@ -15,14 +15,14 @@ sa-token:
|
||||
ticket-timeout: 300
|
||||
# 所有允许的授权回调地址
|
||||
allow-url: "*"
|
||||
# 是否打开单点注销功能
|
||||
is-slo: true
|
||||
|
||||
# ------- SSO-模式三相关配置 (下面的配置在SSO模式三并且 is-slo=true 时打开)
|
||||
|
||||
# ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
|
||||
# 是否打开模式三
|
||||
isHttp: true
|
||||
# 接口调用秘钥(用于SSO模式三的单点注销功能)
|
||||
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
is-http: true
|
||||
sign:
|
||||
# API 接口调用秘钥
|
||||
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
|
||||
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
|
||||
|
||||
spring:
|
||||
|
@ -1,21 +1,17 @@
|
||||
package com.pj.sso;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.dtflys.forest.Forest;
|
||||
|
||||
import cn.dev33.satoken.config.SaSsoConfig;
|
||||
import cn.dev33.satoken.sso.SaSsoProcessor;
|
||||
import cn.dev33.satoken.sso.SaSsoUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.dtflys.forest.Forest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -65,7 +61,7 @@ public class SsoClientController {
|
||||
map.put("loginId", StpUtil.getLoginId());
|
||||
|
||||
// 发起请求
|
||||
Object resData = SaSsoUtil.getData("/sso/getData", map);
|
||||
Object resData = SaSsoUtil.getData(map);
|
||||
System.out.println("sso-server 返回的信息:" + resData);
|
||||
return resData;
|
||||
}
|
||||
|
@ -8,18 +8,17 @@ sa-token:
|
||||
sso:
|
||||
# SSO-Server端 统一认证地址
|
||||
auth-url: http://sa-sso-server.com:9000/sso/auth
|
||||
# 使用Http请求校验ticket
|
||||
# 使用 Http 请求校验ticket (模式三)
|
||||
is-http: true
|
||||
# SSO-Server端 ticket校验地址
|
||||
check-ticket-url: http://sa-sso-server.com:9000/sso/checkTicket
|
||||
# 打开单点注销功能
|
||||
is-slo: true
|
||||
# 单点注销地址
|
||||
slo-url: http://sa-sso-server.com:9000/sso/signout
|
||||
# 接口调用秘钥
|
||||
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
# 查询数据地址
|
||||
get-data-url: http://sa-sso-server.com:9000/sso/getData
|
||||
sign:
|
||||
# API 接口调用秘钥
|
||||
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
|
||||
spring:
|
||||
# 配置 Redis 连接 (此处与SSO-Server端连接不同的Redis)
|
||||
|
@ -184,6 +184,13 @@ public class SsoUserServerController {
|
||||
public StpLogic getStpLogic() {
|
||||
return StpUserUtil.stpLogic;
|
||||
}
|
||||
// 使用自定义的签名秘钥
|
||||
SaSignConfig signConfig = new SaSignConfig().setSecretKey("xxxx-新的秘钥-xxxx");
|
||||
SaSignTemplate userSignTemplate = new SaSignTemplate().setSignConfig(signConfig);
|
||||
@Override
|
||||
public SaSignTemplate getSignTemplate() {
|
||||
return userSignTemplate;
|
||||
}
|
||||
};
|
||||
// 让这个SSO请求处理器,使用的路由前缀是 /sso-user,而不是原先的 /sso
|
||||
ssoUserTemplate.apiName.replacePrefix("/sso-user");
|
||||
|
@ -178,14 +178,13 @@ sa-token:
|
||||
ticket-timeout: 300
|
||||
# 所有允许的授权回调地址
|
||||
allow-url: "*"
|
||||
# 是否打开单点注销功能
|
||||
is-slo: true
|
||||
|
||||
# ------- SSO-模式三相关配置 (下面的配置在SSO模式三并且 is-slo=true 时打开)
|
||||
# ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
|
||||
# 是否打开模式三
|
||||
isHttp: true
|
||||
# 接口调用秘钥(用于SSO模式三的单点注销功能)
|
||||
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
is-http: true
|
||||
sign:
|
||||
# API 接口调用秘钥
|
||||
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
|
||||
|
||||
spring:
|
||||
@ -219,14 +218,12 @@ server.port=9000
|
||||
sa-token.sso.ticket-timeout=300
|
||||
# 所有允许的授权回调地址
|
||||
sa-token.sso.allow-url=*
|
||||
# 是否打开单点注销功能
|
||||
sa-token.sso.is-slo=true
|
||||
|
||||
# ------- SSO-模式三相关配置 (下面的配置在SSO模式三并且 is-slo=true 时打开)
|
||||
# ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
|
||||
# 是否打开模式三
|
||||
sa-token.sso.isHttp=true
|
||||
# 接口调用秘钥(用于SSO模式三的单点注销功能)
|
||||
sa-token.sso.secretkey=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
sa-token.sso.is-http=true
|
||||
# API 接口调用秘钥
|
||||
sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
|
||||
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
|
||||
|
||||
|
@ -173,8 +173,6 @@ sa-token:
|
||||
sso:
|
||||
# SSO-Server端 统一认证地址
|
||||
auth-url: http://sa-sso-server.com:9000/sso/auth
|
||||
# 是否打开单点注销接口
|
||||
is-slo: true
|
||||
|
||||
# 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
|
||||
alone-redis:
|
||||
@ -197,8 +195,6 @@ server.port=9001
|
||||
######### Sa-Token 配置 #########
|
||||
# SSO-Server端 统一认证地址
|
||||
sa-token.sso.auth-url=http://sa-sso-server.com:9000/sso/auth
|
||||
# 是否打开单点注销接口
|
||||
sa-token.sso.is-slo=true
|
||||
|
||||
# 配置 Sa-Token 单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
|
||||
# Redis数据库索引
|
||||
|
@ -115,13 +115,13 @@ forest.log-enabled: false
|
||||
``` java
|
||||
// 示例:获取数据接口(用于在模式三下,为 client 端开放拉取数据的接口)
|
||||
@RequestMapping("/sso/getData")
|
||||
public Object userinfo(String apiType, String loginId) {
|
||||
public Object getData(String apiType, String loginId) {
|
||||
System.out.println("---------------- 获取数据 ----------------");
|
||||
System.out.println("apiType=" + apiType);
|
||||
System.out.println("loginId=" + loginId);
|
||||
|
||||
// 校验签名:只有拥有正确秘钥发起的请求才能通过校验
|
||||
SaSsoUtil.checkSign(SaHolder.getRequest());
|
||||
SaSignUtil.checkRequest(SaHolder.getRequest());
|
||||
|
||||
// 自定义返回结果(模拟)
|
||||
return SaResult.ok()
|
||||
@ -232,7 +232,7 @@ public Object getFansList(Long loginId) {
|
||||
System.out.println("---------------- 获取 loginId=" + loginId + " 的粉丝列表 ----------------");
|
||||
|
||||
// 校验签名:只有拥有正确秘钥发起的请求才能通过校验
|
||||
SaSsoUtil.checkSign(SaHolder.getRequest());
|
||||
SaSignUtil.checkRequest(SaHolder.getRequest());
|
||||
|
||||
// 查询数据 (此处仅做模拟)
|
||||
List<Integer> list = Arrays.asList(10041, 10042, 10043, 10044);
|
||||
@ -284,12 +284,11 @@ sa-token:
|
||||
``` yaml
|
||||
sa-token:
|
||||
sso:
|
||||
# 打开单点注销功能
|
||||
is-slo: true
|
||||
# 单点注销地址
|
||||
slo-url: http://sa-sso-server.com:9000/sso/signout
|
||||
# 接口调用秘钥
|
||||
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
sign:
|
||||
# API 接口调用秘钥
|
||||
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
```
|
||||
<!------------- tab:properties 风格 ------------->
|
||||
``` properties
|
||||
@ -298,7 +297,7 @@ sa-token.sso.is-slo=true
|
||||
# 单点注销地址
|
||||
sa-token.sso.slo-url=http://sa-sso-server.com:9000/sso/signout
|
||||
# 接口调用秘钥
|
||||
sa-token.sso.secretkey=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
```
|
||||
<!---------------------------- tabs:end ---------------------------->
|
||||
|
||||
|
@ -43,11 +43,6 @@ public class SaSsoConfig implements Serializable {
|
||||
*/
|
||||
public Boolean isHttp = false;
|
||||
|
||||
/**
|
||||
* 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
|
||||
*/
|
||||
public String secretkey;
|
||||
|
||||
|
||||
// ----------------- Client端相关配置
|
||||
|
||||
@ -106,17 +101,6 @@ public class SaSsoConfig implements Serializable {
|
||||
*/
|
||||
public String serverUrl;
|
||||
|
||||
// ----------------- 其它
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距
|
||||
*/
|
||||
public long timestampDisparity = 1000 * 60 * 10;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Ticket有效期 (单位: 秒)
|
||||
@ -182,22 +166,6 @@ public class SaSsoConfig implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
|
||||
*/
|
||||
public String getSecretkey() {
|
||||
return secretkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param secretkey 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoConfig setSecretkey(String secretkey) {
|
||||
this.secretkey = secretkey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 当前 Client 名称标识,用于和 ticket 码的互相锁定
|
||||
*/
|
||||
@ -325,30 +293,13 @@ public class SaSsoConfig implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距
|
||||
*/
|
||||
public long getTimestampDisparity() {
|
||||
return timestampDisparity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timestampDisparity 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoConfig setTimestampDisparity(long timestampDisparity) {
|
||||
this.timestampDisparity = timestampDisparity;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaSsoConfig ["
|
||||
+ "ticketTimeout=" + ticketTimeout
|
||||
+ ", allowUrl=" + allowUrl
|
||||
+ ", isSlo=" + isSlo
|
||||
+ ", isHttp=" + isHttp
|
||||
+ ", secretkey=" + secretkey
|
||||
+ ", isHttp=" + isHttp
|
||||
+ ", client=" + client
|
||||
+ ", authUrl=" + authUrl
|
||||
+ ", checkTicketUrl=" + checkTicketUrl
|
||||
@ -356,8 +307,7 @@ public class SaSsoConfig implements Serializable {
|
||||
+ ", userinfoUrl=" + userinfoUrl
|
||||
+ ", sloUrl=" + sloUrl
|
||||
+ ", ssoLogoutCall=" + ssoLogoutCall
|
||||
+ ", serverUrl=" + serverUrl
|
||||
+ ", timestampDisparity=" + timestampDisparity
|
||||
+ ", serverUrl=" + serverUrl
|
||||
+ "]";
|
||||
}
|
||||
|
||||
|
@ -193,7 +193,7 @@ public class SaSsoProcessor {
|
||||
String loginId = req.getParam(paramName.loginId);
|
||||
|
||||
// step.1 校验签名
|
||||
ssoTemplate.checkSign(req);
|
||||
ssoTemplate.getSignTemplate().checkRequest(req);
|
||||
|
||||
// step.2 单点注销
|
||||
ssoTemplate.ssoLogout(loginId);
|
||||
@ -374,7 +374,7 @@ public class SaSsoProcessor {
|
||||
String loginId = req.getParamNotNull(paramName.loginId);
|
||||
|
||||
// 注销当前应用端会话
|
||||
ssoTemplate.checkSign(req);
|
||||
ssoTemplate.getSignTemplate().checkRequest(req);
|
||||
stpLogic.logout(loginId);
|
||||
|
||||
// 响应
|
||||
|
@ -2,8 +2,8 @@ package cn.dev33.satoken.sso;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaSsoConfig;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.sign.SaSignTemplate;
|
||||
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
|
||||
import cn.dev33.satoken.sso.exception.SaSsoException;
|
||||
import cn.dev33.satoken.sso.name.ApiName;
|
||||
@ -68,8 +68,16 @@ public class SaSsoTemplate {
|
||||
public SaSsoConfig getSsoConfig() {
|
||||
return SaSsoManager.getConfig();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取底层使用的 API 签名对象
|
||||
* @return /
|
||||
*/
|
||||
public SaSignTemplate getSignTemplate() {
|
||||
return SaManager.getSaSignTemplate();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------- Ticket 操作 ----------------------
|
||||
|
||||
/**
|
||||
@ -300,7 +308,7 @@ public class SaSsoTemplate {
|
||||
SaSsoConfig cfg = SaSsoManager.getConfig();
|
||||
Set<String> urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, HashSet::new);
|
||||
for (String url : urlSet) {
|
||||
url = addSignParams(url, loginId);
|
||||
url = joinLoginIdAndSign(url, loginId);
|
||||
cfg.getSendHttp().apply(url);
|
||||
}
|
||||
|
||||
@ -452,7 +460,7 @@ public class SaSsoTemplate {
|
||||
*/
|
||||
public String buildSloUrl(Object loginId) {
|
||||
String url = SaSsoManager.getConfig().splicingSloUrl();
|
||||
return addSignParams(url, loginId);
|
||||
return joinLoginIdAndSign(url, loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -480,32 +488,11 @@ public class SaSsoTemplate {
|
||||
}
|
||||
|
||||
// 添加签名等参数,并序列化
|
||||
return addSignParams(url, paramMap);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 返回相应key -------------------
|
||||
|
||||
/**
|
||||
* 拼接key:Ticket 查 账号Id
|
||||
* @param ticket ticket值
|
||||
* @return key
|
||||
*/
|
||||
public String splicingTicketSaveKey(String ticket) {
|
||||
return SaManager.getConfig().getTokenName() + ":ticket:" + ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接key:账号Id 反查 Ticket
|
||||
* @param id 账号id
|
||||
* @return key
|
||||
*/
|
||||
public String splicingTicketIndexKey(Object id) {
|
||||
return SaManager.getConfig().getTokenName() + ":id-ticket:" + id;
|
||||
return joinParamMapAndSign(url, paramMap);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 请求相关 -------------------
|
||||
// ------------------- 发起请求 -------------------
|
||||
|
||||
/**
|
||||
* 发出请求,并返回 SaResult 结果
|
||||
@ -518,33 +505,20 @@ public class SaSsoTemplate {
|
||||
return new SaResult(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取:接口调用秘钥
|
||||
* @return see note
|
||||
*/
|
||||
public String getSecretkey() {
|
||||
// 默认从配置文件中返回
|
||||
String secretkey = SaSsoManager.getConfig().getSecretkey();
|
||||
if(SaFoxUtil.isEmpty(secretkey)) {
|
||||
throw new SaSsoException("请配置 secretkey 参数").setCode(SaSsoErrorCode.CODE_30009);
|
||||
}
|
||||
return secretkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 paramMap 追加 sign 等参数,并序列化为kv字符串,拼接到url后面
|
||||
* @param url 请求地址
|
||||
* @param paramMap 请求原始参数列表
|
||||
* @return 加工后的url
|
||||
*/
|
||||
public String addSignParams(String url, Map<String, Object> paramMap) {
|
||||
// 追加:时间戳、随机字符串、参数签名
|
||||
SaManager.getSaSignTemplate().addSignParams(paramMap, getSecretkey());
|
||||
public String joinParamMapAndSign(String url, Map<String, Object> paramMap) {
|
||||
// 在参数列表中追加:时间戳、随机字符串、参数签名
|
||||
SaManager.getSaSignTemplate().addSignParams(paramMap);
|
||||
|
||||
// 序列化为kv字符串
|
||||
// 将参数列表序列化为kv字符串
|
||||
String signParams = SaManager.getSaSignTemplate().joinParams(paramMap);
|
||||
|
||||
// 拼接到一起
|
||||
// 将kv字符串拼接到url后面
|
||||
return SaFoxUtil.joinParam(url, signParams);
|
||||
}
|
||||
|
||||
@ -554,51 +528,36 @@ public class SaSsoTemplate {
|
||||
* @param loginId 账号id
|
||||
* @return 加工后的url
|
||||
*/
|
||||
public String addSignParams(String url, Object loginId) {
|
||||
public String joinLoginIdAndSign(String url, Object loginId) {
|
||||
Map<String, Object> paramMap = new LinkedHashMap<>();
|
||||
paramMap.put(paramName.loginId, loginId);
|
||||
return addSignParams(url, paramMap);
|
||||
return joinParamMapAndSign(url, paramMap);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 返回相应key -------------------
|
||||
|
||||
/**
|
||||
* 拼接key:Ticket 查 账号Id
|
||||
* @param ticket ticket值
|
||||
* @return key
|
||||
*/
|
||||
public String splicingTicketSaveKey(String ticket) {
|
||||
return SaManager.getConfig().getTokenName() + ":ticket:" + ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验签名
|
||||
* @param req request
|
||||
* 拼接key:账号Id 反查 Ticket
|
||||
* @param id 账号id
|
||||
* @return key
|
||||
*/
|
||||
public void checkSign(SaRequest req) {
|
||||
// 获取签名、时间戳、随机字符串
|
||||
String sign = req.getParamNotNull(paramName.sign);
|
||||
String timestamp = req.getParamNotNull(paramName.timestamp);
|
||||
String nonce = req.getParamNotNull(paramName.nonce);
|
||||
|
||||
// 1、校验时间戳
|
||||
SaManager.getSaSignTemplate().checkTimestamp(Long.parseLong(timestamp), SaSsoManager.getConfig().getTimestampDisparity());
|
||||
|
||||
// 2、校验随机字符串
|
||||
|
||||
// 3、校验签名
|
||||
SaManager.getSaSignTemplate().checkSign(req.getParamMap(), getSecretkey(), sign);
|
||||
public String splicingTicketIndexKey(Object id) {
|
||||
return SaManager.getConfig().getTokenName() + ":id-ticket:" + id;
|
||||
}
|
||||
|
||||
|
||||
// -------- 以下方法已废弃,仅为兼容旧版本而保留 --------
|
||||
|
||||
/**
|
||||
* 根据参数计算签名
|
||||
* @param loginId 账号id
|
||||
* @param timestamp 当前时间戳,13位
|
||||
* @param nonce 随机字符串
|
||||
* @param secretkey 账号id
|
||||
* @return 签名
|
||||
*/
|
||||
@Deprecated
|
||||
public String getSign(Object loginId, String timestamp, String nonce, String secretkey) {
|
||||
Map<String, Object> map = new TreeMap<>();
|
||||
map.put(paramName.loginId, loginId);
|
||||
map.put(paramName.timestamp, timestamp);
|
||||
map.put(paramName.nonce, nonce);
|
||||
return SaManager.getSaSignTemplate().createSign(map, secretkey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:Server端 账号资料查询地址
|
||||
* @param loginId 账号id
|
||||
@ -607,7 +566,7 @@ public class SaSsoTemplate {
|
||||
@Deprecated
|
||||
public String buildUserinfoUrl(Object loginId) {
|
||||
String userinfoUrl = SaSsoManager.getConfig().splicingUserinfoUrl();
|
||||
return addSignParams(userinfoUrl, loginId);
|
||||
return joinLoginIdAndSign(userinfoUrl, loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -618,7 +577,7 @@ public class SaSsoTemplate {
|
||||
@Deprecated
|
||||
public Object getUserinfo(Object loginId) {
|
||||
String url = buildUserinfoUrl(loginId);
|
||||
return SaSsoManager.getConfig().getSendHttp().apply(url);
|
||||
return request(url);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cn.dev33.satoken.sso;
|
||||
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
import java.util.Map;
|
||||
@ -202,7 +201,7 @@ public class SaSsoUtil {
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 请求相关 -------------------
|
||||
// ------------------- 发起请求 -------------------
|
||||
|
||||
/**
|
||||
* 发出请求,并返回 SaResult 结果
|
||||
@ -219,8 +218,8 @@ public class SaSsoUtil {
|
||||
* @param paramMap 请求原始参数列表
|
||||
* @return 加工后的url
|
||||
*/
|
||||
public static String addSignParams(String url, Map<String, Object> paramMap) {
|
||||
return ssoTemplate.addSignParams(url, paramMap);
|
||||
public static String joinParamMapAndSign(String url, Map<String, Object> paramMap) {
|
||||
return ssoTemplate.joinLoginIdAndSign(url, paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -229,32 +228,21 @@ public class SaSsoUtil {
|
||||
* @param loginId 账号id
|
||||
* @return 加工后的url
|
||||
*/
|
||||
public static String addSignParams(String url, Object loginId) {
|
||||
return ssoTemplate.addSignParams(url, loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验签名
|
||||
* @param req request
|
||||
*/
|
||||
public static void checkSign(SaRequest req) {
|
||||
ssoTemplate.checkSign(req);
|
||||
public static String joinLoginIdAndSign(String url, Object loginId) {
|
||||
return ssoTemplate.joinLoginIdAndSign(url, loginId);
|
||||
}
|
||||
|
||||
|
||||
// -------- 以下方法已废弃,仅为兼容旧版本而保留 --------
|
||||
|
||||
/**
|
||||
* 根据参数计算签名
|
||||
* 构建URL:Server端 账号资料查询地址
|
||||
* @param loginId 账号id
|
||||
* @param timestamp 当前时间戳,13位
|
||||
* @param nonce 随机字符串
|
||||
* @param secretkey 账号id
|
||||
* @return 签名
|
||||
* @return Server端 账号资料查询地址
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getSign(Object loginId, String timestamp, String nonce, String secretkey) {
|
||||
return ssoTemplate.getSign(loginId, timestamp, nonce, secretkey);
|
||||
public static String buildUserinfoUrl(Object loginId) {
|
||||
return ssoTemplate.buildUserinfoUrl(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -267,14 +255,4 @@ public class SaSsoUtil {
|
||||
return ssoTemplate.getUserinfo(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:Server端 账号资料查询地址
|
||||
* @param loginId 账号id
|
||||
* @return Server端 账号资料查询地址
|
||||
*/
|
||||
@Deprecated
|
||||
public static String buildUserinfoUrl(Object loginId) {
|
||||
return ssoTemplate.buildUserinfoUrl(loginId);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user