refactor: API Sign 模块拆分独立插件包:sa-token-sign
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
<module>sa-token-sso</module>
|
||||
<module>sa-token-oauth2</module>
|
||||
<module>sa-token-apikey</module>
|
||||
<module>sa-token-sign</module>
|
||||
<module>sa-token-redisson</module>
|
||||
<module>sa-token-redisx</module>
|
||||
<module>sa-token-serializer-features</module>
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.apikey.error;
|
||||
|
||||
/**
|
||||
* 定义 sa-token-apikey 模块所有异常细分状态码
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public interface SaApiKeyErrorCode {
|
||||
|
||||
/** 无效 API Key */
|
||||
int CODE_12301 = 12301;
|
||||
|
||||
/** API Key 已过期 */
|
||||
int CODE_12302 = 12302;
|
||||
|
||||
/** API Key 已被禁用 */
|
||||
int CODE_12303 = 12303;
|
||||
|
||||
/** API Key 字段自检未通过 */
|
||||
int CODE_12304 = 12304;
|
||||
|
||||
/** 未开启索引记录功能却调用了相关 API */
|
||||
int CODE_12305 = 12305;
|
||||
|
||||
/** API Key 不具有指定 Scope */
|
||||
int CODE_12311 = 12311;
|
||||
|
||||
/** API Key 不属于指定用户 */
|
||||
int CODE_12312 = 12312;
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.apikey.exception;
|
||||
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ApiKey 相关错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.42.0
|
||||
*/
|
||||
public class ApiKeyException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ApiKey 相关错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public ApiKeyException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ApiKey 相关错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public ApiKeyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体引起异常的 ApiKey 值
|
||||
*/
|
||||
public String apiKey;
|
||||
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
public ApiKeyException setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new ApiKeyException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.apikey.exception;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ApiKey Scope 相关错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.42.0
|
||||
*/
|
||||
public class ApiKeyScopeException extends ApiKeyException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ApiKey Scope 相关错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public ApiKeyScopeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ApiKey Scope 相关错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public ApiKeyScopeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体引起异常的 ApiKey 值
|
||||
*/
|
||||
public String apiKey;
|
||||
|
||||
/**
|
||||
* 具体引起异常的 scope 值
|
||||
*/
|
||||
public String scope;
|
||||
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
public ApiKeyScopeException setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public ApiKeyScopeException setScope(String scope) {
|
||||
this.scope = scope;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new ApiKeyScopeException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+7
-7
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package cn.dev33.satoken.apikey.model;
|
||||
|
||||
import cn.dev33.satoken.apikey.error.SaApiKeyErrorCode;
|
||||
import cn.dev33.satoken.apikey.exception.ApiKeyException;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.ApiKeyException;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -140,19 +140,19 @@ public class ApiKeyModel implements Serializable {
|
||||
*/
|
||||
public void checkByCanSaved() {
|
||||
if (SaFoxUtil.isEmpty(this.apiKey)) {
|
||||
throw new ApiKeyException("ApiKey 值不可为空").setApiKey(apiKey).setCode(SaErrorCode.CODE_12304);
|
||||
throw new ApiKeyException("ApiKey 值不可为空").setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
|
||||
}
|
||||
if (this.loginId == null) {
|
||||
throw new ApiKeyException("无效 ApiKey: " + apiKey).setApiKey(apiKey).setCode(SaErrorCode.CODE_12304);
|
||||
throw new ApiKeyException("无效 ApiKey: " + apiKey).setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
|
||||
}
|
||||
if (this.createTime == 0) {
|
||||
throw new ApiKeyException("请指定 createTime 创建时间").setApiKey(apiKey).setCode(SaErrorCode.CODE_12304);
|
||||
throw new ApiKeyException("请指定 createTime 创建时间").setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
|
||||
}
|
||||
if (this.expiresTime == 0) {
|
||||
throw new ApiKeyException("请指定 expiresTime 过期时间").setApiKey(apiKey).setCode(SaErrorCode.CODE_12304);
|
||||
throw new ApiKeyException("请指定 expiresTime 过期时间").setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
|
||||
}
|
||||
if (this.isValid == null) {
|
||||
throw new ApiKeyException("请指定 isValid 是否生效").setApiKey(apiKey).setCode(SaErrorCode.CODE_12304);
|
||||
throw new ApiKeyException("请指定 isValid 是否生效").setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -17,14 +17,14 @@ package cn.dev33.satoken.apikey.template;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.apikey.SaApiKeyManager;
|
||||
import cn.dev33.satoken.apikey.error.SaApiKeyErrorCode;
|
||||
import cn.dev33.satoken.apikey.exception.ApiKeyException;
|
||||
import cn.dev33.satoken.apikey.exception.ApiKeyScopeException;
|
||||
import cn.dev33.satoken.apikey.model.ApiKeyModel;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.ApiKeyException;
|
||||
import cn.dev33.satoken.exception.ApiKeyScopeException;
|
||||
import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.session.raw.SaRawSessionDelegator;
|
||||
@@ -124,13 +124,13 @@ public class SaApiKeyTemplate {
|
||||
public ApiKeyModel checkApiKey(String apiKey) {
|
||||
ApiKeyModel ak = getApiKey(apiKey);
|
||||
if(ak == null) {
|
||||
throw new ApiKeyException("无效 API Key: " + apiKey).setApiKey(apiKey).setCode(SaErrorCode.CODE_12301);
|
||||
throw new ApiKeyException("无效 API Key: " + apiKey).setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12301);
|
||||
}
|
||||
if(ak.timeExpired()) {
|
||||
throw new ApiKeyException("API Key 已过期: " + apiKey).setApiKey(apiKey).setCode(SaErrorCode.CODE_12302);
|
||||
throw new ApiKeyException("API Key 已过期: " + apiKey).setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12302);
|
||||
}
|
||||
if(! ak.getIsValid()) {
|
||||
throw new ApiKeyException("API Key 已被禁用: " + apiKey).setApiKey(apiKey).setCode(SaErrorCode.CODE_12303);
|
||||
throw new ApiKeyException("API Key 已被禁用: " + apiKey).setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12303);
|
||||
}
|
||||
return ak;
|
||||
}
|
||||
@@ -315,7 +315,7 @@ public class SaApiKeyTemplate {
|
||||
throw new ApiKeyScopeException("该 API Key 不具备 Scope:" + scope)
|
||||
.setApiKey(apiKey)
|
||||
.setScope(scope)
|
||||
.setCode(SaErrorCode.CODE_12311);
|
||||
.setCode(SaApiKeyErrorCode.CODE_12311);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,7 +352,7 @@ public class SaApiKeyTemplate {
|
||||
throw new ApiKeyScopeException("该 API Key 不具备 Scope:" + scopes[0])
|
||||
.setApiKey(apiKey)
|
||||
.setScope(scopes[0])
|
||||
.setCode(SaErrorCode.CODE_12311);
|
||||
.setCode(SaApiKeyErrorCode.CODE_12311);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,12 +378,12 @@ public class SaApiKeyTemplate {
|
||||
public void checkApiKeyLoginId(String apiKey, Object loginId) {
|
||||
ApiKeyModel ak = getApiKey(apiKey);
|
||||
if(ak == null) {
|
||||
throw new ApiKeyException("无效 API Key: " + apiKey).setApiKey(apiKey).setCode(SaErrorCode.CODE_12301);
|
||||
throw new ApiKeyException("无效 API Key: " + apiKey).setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12301);
|
||||
}
|
||||
if (SaFoxUtil.notEquals(String.valueOf(ak.getLoginId()), String.valueOf(loginId))) {
|
||||
throw new ApiKeyException("该 API Key 不属于用户: " + loginId)
|
||||
.setApiKey(apiKey)
|
||||
.setCode(SaErrorCode.CODE_12312);
|
||||
.setCode(SaApiKeyErrorCode.CODE_12312);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@
|
||||
<artifactId>sa-token-jwt</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- sa-token-sign 校验 nonce -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-sign</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package cn.dev33.satoken.oauth2.scope.handler;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.jwt.SaJwtUtil;
|
||||
@@ -29,6 +28,7 @@ import cn.dev33.satoken.oauth2.data.model.oidc.IdTokenModel;
|
||||
import cn.dev33.satoken.oauth2.data.model.request.ClientIdAndSecretModel;
|
||||
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
|
||||
import cn.dev33.satoken.oauth2.scope.CommonScope;
|
||||
import cn.dev33.satoken.sign.SaSignManager;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
@@ -127,7 +127,7 @@ public class OidcScopeHandler implements SaOAuth2ScopeHandlerInterface {
|
||||
if(SaFoxUtil.isEmpty(nonce)) {
|
||||
nonce = SaFoxUtil.getRandomString(32);
|
||||
}
|
||||
SaManager.getSaSignTemplate().checkNonce(nonce);
|
||||
SaSignManager.getSaSignTemplate().checkNonce(nonce);
|
||||
return nonce;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sa-token-plugin</artifactId>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sa-token-sign</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.plugin;
|
||||
|
||||
import cn.dev33.satoken.sign.annotation.handle.SaCheckSignHandler;
|
||||
import cn.dev33.satoken.strategy.SaAnnotationStrategy;
|
||||
|
||||
/**
|
||||
* SaToken 插件安装:API 参数签名 组件
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public class SaTokenPluginForSign implements SaTokenPlugin {
|
||||
|
||||
@Override
|
||||
public void install() {
|
||||
// 安装 API 参数签名 鉴权注解
|
||||
SaAnnotationStrategy.instance.registerAnnotationHandler(new SaCheckSignHandler());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.listener.SaTokenEventCenter;
|
||||
import cn.dev33.satoken.sign.config.SaSignConfig;
|
||||
import cn.dev33.satoken.sign.template.SaSignTemplate;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 管理 Sa-Token API 参数签名 所有全局组件
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public class SaSignManager {
|
||||
|
||||
/**
|
||||
* API 参数签名 配置 Bean
|
||||
*/
|
||||
private static volatile SaSignConfig config;
|
||||
public static SaSignConfig getConfig() {
|
||||
if (config == null) {
|
||||
// 初始化默认值
|
||||
synchronized (SaSignManager.class) {
|
||||
if (config == null) {
|
||||
setConfig(new SaSignConfig());
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
public static void setConfig(SaSignConfig config) {
|
||||
SaSignManager.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* API 签名配置 多实例 配置 Bean
|
||||
*/
|
||||
private static volatile Map<String, SaSignConfig> signMany;
|
||||
public static Map<String, SaSignConfig> getSignMany() {
|
||||
if (signMany == null) {
|
||||
// 初始化默认值
|
||||
synchronized (SaSignManager.class) {
|
||||
if (signMany == null) {
|
||||
setSignMany(new LinkedHashMap<>());
|
||||
}
|
||||
}
|
||||
}
|
||||
return signMany;
|
||||
}
|
||||
public static void setSignMany(Map<String, SaSignConfig> signMany) {
|
||||
SaSignManager.signMany = signMany;
|
||||
}
|
||||
|
||||
/**
|
||||
* API 参数签名
|
||||
*/
|
||||
private volatile static SaSignTemplate saSignTemplate;
|
||||
public static void setSaSignTemplate(SaSignTemplate saSignTemplate) {
|
||||
SaSignManager.saSignTemplate = saSignTemplate;
|
||||
SaTokenEventCenter.doRegisterComponent("SaSignTemplate", saSignTemplate);
|
||||
}
|
||||
public static SaSignTemplate getSaSignTemplate() {
|
||||
if (saSignTemplate == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saSignTemplate == null) {
|
||||
SaSignManager.saSignTemplate = new SaSignTemplate();
|
||||
}
|
||||
}
|
||||
}
|
||||
return saSignTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* API 参数签名校验:必须具有正确的参数签名才可以通过校验
|
||||
*
|
||||
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.41.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD,ElementType.TYPE})
|
||||
public @interface SaCheckSign {
|
||||
|
||||
/**
|
||||
* 多实例下的 appid 值,用于区分不同的实例,如不填写则代表使用全局默认实例 <br/>
|
||||
* 允许以 #{} 的形式指定为请求参数,如:#{appid}
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String appid() default "";
|
||||
|
||||
/**
|
||||
* 指定参与签名的参数有哪些,如果不填写则默认为全部参数
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String [] verifyParams() default {};
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign.annotation.handle;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.sign.annotation.SaCheckSign;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.sign.template.SaSignMany;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckSign 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.41.0
|
||||
*/
|
||||
public class SaCheckSignHandler implements SaAnnotationHandlerInterface<SaCheckSign> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckSign> getHandlerAnnotationClass() {
|
||||
return SaCheckSign.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckSign at, AnnotatedElement element) {
|
||||
_checkMethod(at.appid(), at.verifyParams());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String appid, String[] verifyParams) {
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
// 如果 appid 为 #{} 格式,则从请求参数中获取
|
||||
if(appid.startsWith("#{") && appid.endsWith("}")) {
|
||||
String reqParamName = appid.substring(2, appid.length() - 1);
|
||||
appid = req.getParam(reqParamName);
|
||||
}
|
||||
SaSignMany.getSignTemplate(appid).checkRequest(req, verifyParams);
|
||||
}
|
||||
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign.config;
|
||||
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.fun.SaParamRetFunction;
|
||||
import cn.dev33.satoken.secure.SaSecureUtil;
|
||||
|
||||
/**
|
||||
* Sa-Token API 接口签名/验签 相关配置类
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.34.0
|
||||
*/
|
||||
public class SaSignConfig {
|
||||
|
||||
/**
|
||||
* API 调用签名秘钥
|
||||
*/
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* 接口调用时的时间戳允许的差距(单位:ms),-1 代表不校验差距,默认15分钟
|
||||
*
|
||||
* <p> 比如此处你配置了60秒,当一个请求从 client 发起后,如果 server 端60秒内没有处理,60秒后再想处理就无法校验通过了。</p>
|
||||
* <p> timestamp + nonce 有效防止重放攻击。 </p>
|
||||
*/
|
||||
private long timestampDisparity = 1000 * 60 * 15;
|
||||
|
||||
/**
|
||||
* 对 fullStr 的摘要算法
|
||||
*/
|
||||
private String digestAlgo = "md5";
|
||||
|
||||
public SaSignConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param secretKey 秘钥
|
||||
*/
|
||||
public SaSignConfig(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
|
||||
// -------------- 扩展方法
|
||||
|
||||
/**
|
||||
* 计算保存 nonce 时应该使用的 ttl,单位:秒
|
||||
* @return /
|
||||
*/
|
||||
public long getSaveNonceExpire() {
|
||||
// 如果 timestampDisparity >= 0,则 nonceTtl 的值等于 timestampDisparity 的值,单位转秒
|
||||
if(timestampDisparity >= 0) {
|
||||
return timestampDisparity / 1000;
|
||||
}
|
||||
// 否则,nonceTtl 的值为 24 小时
|
||||
else {
|
||||
return 60 * 60 * 24;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制对象
|
||||
* @return /
|
||||
*/
|
||||
public SaSignConfig copy() {
|
||||
SaSignConfig obj = new SaSignConfig();
|
||||
obj.secretKey = this.secretKey;
|
||||
obj.timestampDisparity = this.timestampDisparity;
|
||||
obj.digestAlgo = this.digestAlgo;
|
||||
obj.digestMethod = this.digestMethod;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
// -------------- 策略函数
|
||||
|
||||
/**
|
||||
* 对 fullStr 的摘要算法函数
|
||||
*/
|
||||
public SaParamRetFunction<String, String> digestMethod = (fullStr) -> {
|
||||
// md5
|
||||
if(digestAlgo.equalsIgnoreCase("md5")) {
|
||||
return SaSecureUtil.md5(fullStr);
|
||||
}
|
||||
// sha1
|
||||
if(digestAlgo.equalsIgnoreCase("sha1")) {
|
||||
return SaSecureUtil.sha1(fullStr);
|
||||
}
|
||||
// sha256
|
||||
if(digestAlgo.equalsIgnoreCase("sha256")) {
|
||||
return SaSecureUtil.sha256(fullStr);
|
||||
}
|
||||
// sha384
|
||||
if(digestAlgo.equalsIgnoreCase("sha384")) {
|
||||
return SaSecureUtil.sha384(fullStr);
|
||||
}
|
||||
// sha512
|
||||
if(digestAlgo.equalsIgnoreCase("sha512")) {
|
||||
return SaSecureUtil.sha512(fullStr);
|
||||
}
|
||||
// 未知
|
||||
throw new SaTokenException("不支持的摘要算法:" + digestAlgo + ",你可以自定义摘要算法函数实现");
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置: 对 fullStr 的摘要算法函数
|
||||
*
|
||||
* @param digestMethod /
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSignConfig setDigestMethod(SaParamRetFunction<String, String> digestMethod) {
|
||||
this.digestMethod = digestMethod;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -------------- get/set
|
||||
|
||||
/**
|
||||
* 获取 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分钟
|
||||
*
|
||||
* <p> 比如此处你配置了60秒,当一个请求从 client 发起后,如果 server 端60秒内没有处理,60秒后再想处理就无法校验通过了。</p>
|
||||
* <p> timestamp + nonce 有效防止重放攻击。 </p>
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public long getTimestampDisparity() {
|
||||
return this.timestampDisparity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 接口调用时的时间戳允许的差距(单位:ms),-1 代表不校验差距,默认15分钟
|
||||
*
|
||||
* <p> 比如此处你配置了60秒,当一个请求从 client 发起后,如果 server 端60秒内没有处理,60秒后再想处理就无法校验通过了。</p>
|
||||
* <p> timestamp + nonce 有效防止重放攻击。 </p>
|
||||
*
|
||||
* @param timestampDisparity /
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSignConfig setTimestampDisparity(long timestampDisparity) {
|
||||
this.timestampDisparity = timestampDisparity;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 对 fullStr 的摘要算法
|
||||
*
|
||||
* @return digestAlgo 对 fullStr 的摘要算法
|
||||
*/
|
||||
public String getDigestAlgo() {
|
||||
return this.digestAlgo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 对 fullStr 的摘要算法
|
||||
* @param digestAlgo /
|
||||
* @return /
|
||||
*/
|
||||
public SaSignConfig setDigestAlgo(String digestAlgo) {
|
||||
this.digestAlgo = digestAlgo;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaSignConfig ["
|
||||
+ "secretKey=" + secretKey
|
||||
+ ", timestampDisparity=" + timestampDisparity
|
||||
+ "]";
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SaSignManyConfig 配置包装类,以更方便框架完成属性注入操作
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public class SaSignManyConfigWrapper {
|
||||
|
||||
public Map<String, SaSignConfig> signMany = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取
|
||||
*
|
||||
* @return signMany
|
||||
*/
|
||||
public Map<String, SaSignConfig> getSignMany() {
|
||||
return this.signMany;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置
|
||||
*
|
||||
* @param signMany
|
||||
*/
|
||||
public void setSignMany(Map<String, SaSignConfig> signMany) {
|
||||
this.signMany = signMany;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaSignManyConfigWrapper{" +
|
||||
"signMany=" + signMany +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign.error;
|
||||
|
||||
/**
|
||||
* 定义 sa-token-sign 模块所有异常细分状态码
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public interface SaSignErrorCode {
|
||||
|
||||
/** 参与参数签名的秘钥不可为空 */
|
||||
int CODE_12201 = 12201;
|
||||
|
||||
/** 给定的签名无效 */
|
||||
int CODE_12202 = 12202;
|
||||
|
||||
/** timestamp 超出允许的范围 */
|
||||
int CODE_12203 = 12203;
|
||||
|
||||
/** 未找到对应 appid 的 SaSignConfig */
|
||||
int CODE_12211 = 12211;
|
||||
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign.exception;
|
||||
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 API 参数签名校验失败
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.34.0
|
||||
*/
|
||||
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 notTrue(boolean flag, String message) {
|
||||
// notTrue
|
||||
if(flag) {
|
||||
throw new SaSignException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言 value 不为空,否则抛出 message 异常
|
||||
* @param value 值
|
||||
* @param message 异常信息
|
||||
*/
|
||||
public static void notEmpty(Object value, String message) {
|
||||
if(SaFoxUtil.isEmpty(value)) {
|
||||
throw new SaSignException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 已过期 -------------------
|
||||
|
||||
/**
|
||||
* 如果flag==true,则抛出message异常
|
||||
* <h2>已过期:请使用 notTrue 代替,用法不变</h2>
|
||||
*
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
*/
|
||||
@Deprecated
|
||||
public static void throwBy(boolean flag, String message) {
|
||||
if(flag) {
|
||||
throw new SaSignException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 value isEmpty,则抛出 message 异常
|
||||
* <h2>已过期:请使用 notEmpty 代替,用法不变</h2>
|
||||
*
|
||||
* @param value 值
|
||||
* @param message 异常信息
|
||||
*/
|
||||
@Deprecated
|
||||
public static void throwByNull(Object value, String message) {
|
||||
if(SaFoxUtil.isEmpty(value)) {
|
||||
throw new SaSignException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign.template;
|
||||
|
||||
import cn.dev33.satoken.fun.SaParamRetFunction;
|
||||
import cn.dev33.satoken.sign.SaSignManager;
|
||||
import cn.dev33.satoken.sign.config.SaSignConfig;
|
||||
import cn.dev33.satoken.sign.error.SaSignErrorCode;
|
||||
import cn.dev33.satoken.sign.exception.SaSignException;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* API 参数签名算法 - 多实例总控类
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.41.0
|
||||
*/
|
||||
public class SaSignMany {
|
||||
|
||||
/**
|
||||
* 根据 appid 获取 SaSignConfig,允许自定义
|
||||
*/
|
||||
public static SaParamRetFunction<String, SaSignConfig> findSaSignConfigMethod = (appid) -> {
|
||||
return SaSignManager.getSignMany().get(appid);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取 SaSignTemplate,根据 appid
|
||||
* @param appid /
|
||||
* @return /
|
||||
*/
|
||||
public static SaSignTemplate getSignTemplate(String appid) {
|
||||
|
||||
// appid 为空,返回全局默认 SaSignTemplate
|
||||
if(SaFoxUtil.isEmpty(appid)){
|
||||
return SaSignManager.getSaSignTemplate();
|
||||
}
|
||||
|
||||
// 获取 SaSignConfig
|
||||
SaSignConfig config = findSaSignConfigMethod.run(appid);
|
||||
if(config == null){
|
||||
throw new SaSignException("未找到签名配置,appid=" + appid).setCode(SaSignErrorCode.CODE_12211);
|
||||
}
|
||||
|
||||
// 创建 SaSignTemplate 并返回
|
||||
return new SaSignTemplate(config);
|
||||
}
|
||||
|
||||
}
|
||||
+417
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign.template;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.sign.error.SaSignErrorCode;
|
||||
import cn.dev33.satoken.sign.exception.SaSignException;
|
||||
import cn.dev33.satoken.sign.SaSignManager;
|
||||
import cn.dev33.satoken.sign.config.SaSignConfig;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static cn.dev33.satoken.SaManager.log;
|
||||
|
||||
/**
|
||||
* API 参数签名算法,在跨系统接口调用时防参数篡改、防重放攻击。
|
||||
*
|
||||
* <p>
|
||||
* 以 SSO 数据拉取为例,流程大致如下:
|
||||
* <br> 1. 以 md5( loginId={账号id}8nonce={随机字符串}8timestamp={13位时间戳}8key={secretkey秘钥} ) 生成签名 sign。
|
||||
* <br> 2. 将 sign 作为参数,拼接到请求地址后面,如:http://xxx.com?loginId=100018nonce=xxx8timestamp=xxx8sign=xxx。
|
||||
* <br> 3. 服务端接收到请求后,以同样的算法生成一次 sign 。
|
||||
* <br> 4. 对比两次 sign 是否一致,一致则通过,否则拒绝 。
|
||||
* </p>
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.30.0
|
||||
*/
|
||||
public class SaSignTemplate {
|
||||
|
||||
public SaSignTemplate() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param signConfig 签名参数配置对象
|
||||
*/
|
||||
public SaSignTemplate(SaSignConfig signConfig) {
|
||||
this.signConfig = signConfig;
|
||||
}
|
||||
|
||||
// ----------- 签名配置
|
||||
|
||||
SaSignConfig signConfig;
|
||||
|
||||
/**
|
||||
* 获取:API 签名配置
|
||||
* @return /
|
||||
*/
|
||||
public SaSignConfig getSignConfig() {
|
||||
return signConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取:API 签名配置:
|
||||
* 1. 如果用户自定义了 signConfig ,则使用用户自定义的。
|
||||
* 2. 否则使用全局默认配置。
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public SaSignConfig getSignConfigOrGlobal() {
|
||||
// 如果用户自定义了 signConfig ,则使用用户自定义的
|
||||
if(signConfig != null) {
|
||||
return signConfig;
|
||||
}
|
||||
// 否则使用全局默认配置
|
||||
return SaSignManager.getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取: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 String joinParams(Map<String, ?> paramsMap) {
|
||||
|
||||
// 按照 k1=v1&k2=v2&k3=v3 排列
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String key : paramsMap.keySet()) {
|
||||
Object value = paramsMap.get(key);
|
||||
if( ! SaFoxUtil.isEmpty(value) ) {
|
||||
sb.append(key).append("=").append(value).append("&");
|
||||
}
|
||||
}
|
||||
|
||||
// 删除最后一位 &
|
||||
if(sb.length() > 0) {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
|
||||
// .
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有参数按照字典顺序连接成一个字符串,形如:a=18b=28c=3
|
||||
* @param paramsMap 参数列表
|
||||
* @return 拼接出的参数字符串
|
||||
*/
|
||||
public String joinParamsDictSort(Map<String, ?> paramsMap) {
|
||||
// 保证字段按照字典顺序排列
|
||||
if( ! (paramsMap instanceof TreeMap) ) {
|
||||
paramsMap = new TreeMap<>(paramsMap);
|
||||
}
|
||||
|
||||
// 拼接
|
||||
return joinParams(paramsMap);
|
||||
}
|
||||
|
||||
|
||||
// ----------- 创建签名
|
||||
|
||||
/**
|
||||
* 创建签名:md5(paramsStr + keyStr)
|
||||
* @param paramsMap 参数列表
|
||||
* @return 签名
|
||||
*/
|
||||
public String createSign(Map<String, ?> paramsMap) {
|
||||
String secretKey = getSecretKey();
|
||||
SaSignException.notEmpty(secretKey, "参与参数签名的秘钥不可为空", SaSignErrorCode.CODE_12201);
|
||||
|
||||
// 如果调用者不小心传入了 sign 参数,则此处需要将 sign 参数排除在外
|
||||
if(paramsMap.containsKey(sign)) {
|
||||
// 为了保证不影响原有的 paramsMap,此处需要再复制一份
|
||||
paramsMap = new TreeMap<>(paramsMap);
|
||||
paramsMap.remove(sign);
|
||||
}
|
||||
|
||||
// 计算签名
|
||||
String paramsStr = joinParamsDictSort(paramsMap);
|
||||
String fullStr = paramsStr + "&" + key + "=" + secretKey;
|
||||
String signStr = digestFullStr(fullStr);
|
||||
|
||||
// 输入日志,方便调试
|
||||
log.debug("fullStr:{}", fullStr);
|
||||
log.debug("signStr:{}", signStr);
|
||||
|
||||
// 返回
|
||||
return signStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用摘要算法创建签名
|
||||
* @param fullStr 待摘要的字符串
|
||||
* @return 签名
|
||||
*/
|
||||
public String digestFullStr(String fullStr) {
|
||||
return getSignConfigOrGlobal().digestMethod.run(fullStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数
|
||||
* @param paramsMap 参数列表
|
||||
* @return 加工后的参数列表
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数,并转换为参数字符串,形如:
|
||||
* <code>data=xxx8nonce=xxx8timestamp=xxx8sign=xxx</code>
|
||||
* @param paramsMap 参数列表
|
||||
* @return 加工后的参数列表 转化为的参数字符串
|
||||
*/
|
||||
public String addSignParamsAndJoin(Map<String, Object> paramsMap) {
|
||||
// 追加参数
|
||||
paramsMap = addSignParams(paramsMap);
|
||||
|
||||
// 拼接参数
|
||||
return joinParams(paramsMap);
|
||||
}
|
||||
|
||||
|
||||
// ----------- 校验签名
|
||||
|
||||
/**
|
||||
* 判断:指定时间戳与当前时间戳的差距是否在允许的范围内
|
||||
* @param timestamp 待校验的时间戳
|
||||
* @return 是否在允许的范围内
|
||||
*/
|
||||
public boolean isValidTimestamp(long timestamp) {
|
||||
long allowDisparity = getSignConfigOrGlobal().getTimestampDisparity();
|
||||
long disparity = Math.abs(System.currentTimeMillis() - timestamp);
|
||||
return allowDisparity == -1 || disparity <= allowDisparity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:指定时间戳与当前时间戳的差距是否在允许的范围内,如果超出则抛出异常
|
||||
* @param timestamp 待校验的时间戳
|
||||
*/
|
||||
public void checkTimestamp(long timestamp) {
|
||||
if( ! isValidTimestamp(timestamp) ) {
|
||||
throw new SaSignException("timestamp 超出允许的范围:" + timestamp).setCode(SaSignErrorCode.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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:随机字符串 nonce 是否有效,如果无效则抛出异常。
|
||||
* 注意:同一 nonce 只可以被校验通过一次,校验后将保存在缓存中,再次校验将无法通过
|
||||
* @param nonce 待校验的随机字符串
|
||||
*/
|
||||
public void checkNonce(String nonce) {
|
||||
// 为空代表无效
|
||||
if(SaFoxUtil.isEmpty(nonce)) {
|
||||
throw new SaSignException("nonce 为空,无效");
|
||||
}
|
||||
|
||||
// 校验此 nonce 是否已被使用过
|
||||
String key = splicingNonceSaveKey(nonce);
|
||||
if(SaManager.getSaTokenDao().get(key) != null) {
|
||||
throw new SaSignException("此 nonce 已被使用过,不可重复使用:" + nonce);
|
||||
}
|
||||
|
||||
// 校验通过后,将此 nonce 保存在缓存中,保证下次校验无法通过
|
||||
SaManager.getSaTokenDao().set(key, nonce, getSignConfigOrGlobal().getSaveNonceExpire() * 2 + 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:给定的参数 生成的签名是否为有效签名
|
||||
* @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(SaSignErrorCode.CODE_12202);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:参数列表中的 nonce、timestamp、sign 是否均为合法的
|
||||
* @param paramMap 待校验的请求参数集合
|
||||
* @return 是否合法
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public boolean isValidParamMap(Map<String, String> paramMap) {
|
||||
// 获取必须的三个参数
|
||||
String timestampValue = paramMap.get(timestamp);
|
||||
String nonceValue = paramMap.get(nonce);
|
||||
String signValue = paramMap.get(sign);
|
||||
|
||||
// 参数非空校验
|
||||
// 配置isCheckNonce=false时,可以不传 nonce
|
||||
if(SaFoxUtil.isEmpty(timestampValue) || SaFoxUtil.isEmpty(signValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 三个值的校验必须全部通过
|
||||
return isValidTimestamp(Long.parseLong(timestampValue))
|
||||
&& isValidNonce(nonceValue)
|
||||
&& 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);
|
||||
|
||||
// 参数非空校验
|
||||
SaSignException.notEmpty(timestampValue, "缺少 timestamp 字段");
|
||||
SaSignException.notEmpty(nonceValue, "缺少 nonce 字段");
|
||||
SaSignException.notEmpty(signValue, "缺少 sign 字段");
|
||||
|
||||
// 依次校验三个参数
|
||||
checkTimestamp(Long.parseLong(timestampValue));
|
||||
checkNonce(nonceValue);
|
||||
checkSign(paramMap, signValue);
|
||||
|
||||
// 通过 √
|
||||
}
|
||||
|
||||
|
||||
// ----------- Web 请求相关 封装
|
||||
|
||||
/**
|
||||
* 判断:一个请求中的 nonce、timestamp、sign 是否均为合法的
|
||||
* @param request 待校验的请求对象
|
||||
* @param paramNames 指定参与签名的参数有哪些,如果不填写则默认为全部参数
|
||||
* @return 是否合法
|
||||
*/
|
||||
public boolean isValidRequest(SaRequest request, String... paramNames) {
|
||||
if(paramNames.length == 0) {
|
||||
return isValidParamMap(request.getParamMap());
|
||||
} else {
|
||||
return isValidParamMap(takeRequestParam(request, paramNames));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:一个请求的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
|
||||
* @param request 待校验的请求对象
|
||||
* @param paramNames 指定参与签名的参数有哪些,如果不填写则默认为全部参数
|
||||
*/
|
||||
public void checkRequest(SaRequest request, String... paramNames) {
|
||||
if (paramNames.length == 0) {
|
||||
checkParamMap(request.getParamMap());
|
||||
} else {
|
||||
checkParamMap(takeRequestParam(request, paramNames));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求中提取指定的参数
|
||||
* @param request 请求对象
|
||||
* @param paramNames 指定的参数名称,不可为空,如果传入空数组则代表只拿 timestamp、nonce、sign 三个参数
|
||||
* @return 提取出的参数
|
||||
*/
|
||||
protected Map<String, String> takeRequestParam(SaRequest request, String [] paramNames) {
|
||||
Map<String, String> paramMap = new TreeMap<>();
|
||||
|
||||
// 此三个参数是必须获取的
|
||||
paramMap.put(timestamp, request.getParam(timestamp));
|
||||
paramMap.put(nonce, request.getParam(nonce));
|
||||
paramMap.put(sign, request.getParam(sign));
|
||||
|
||||
// 获取指定的参数
|
||||
for (String paramName : paramNames) {
|
||||
paramMap.put(paramName, request.getParam(paramName));
|
||||
}
|
||||
|
||||
// 返回
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
// ------------------- 返回相应key -------------------
|
||||
|
||||
/**
|
||||
* 拼接key:存储 nonce 时使用的 key
|
||||
* @param nonce nonce 值
|
||||
* @return key
|
||||
*/
|
||||
public String splicingNonceSaveKey(String nonce) {
|
||||
return SaManager.getConfig().getTokenName() + ":sign:nonce:" + nonce;
|
||||
}
|
||||
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.sign.template;
|
||||
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.sign.SaSignManager;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* API 参数签名算法 - 工具类
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.34.0
|
||||
*/
|
||||
public class SaSignUtil {
|
||||
|
||||
// ----------- 拼接参数
|
||||
|
||||
/**
|
||||
* 将所有参数连接成一个字符串(不排序),形如:b=28a=18c=3
|
||||
* @param paramsMap 参数列表
|
||||
* @return 拼接出的参数字符串
|
||||
*/
|
||||
public static String joinParams(Map<String, ?> paramsMap) {
|
||||
return SaSignManager.getSaSignTemplate().joinParams(paramsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有参数按照字典顺序连接成一个字符串,形如:a=18b=28c=3
|
||||
* @param paramsMap 参数列表
|
||||
* @return 拼接出的参数字符串
|
||||
*/
|
||||
public static String joinParamsDictSort(Map<String, ?> paramsMap) {
|
||||
return SaSignManager.getSaSignTemplate().joinParamsDictSort(paramsMap);
|
||||
}
|
||||
|
||||
|
||||
// ----------- 创建签名
|
||||
|
||||
/**
|
||||
* 创建签名:md5(paramsStr + keyStr)
|
||||
* @param paramsMap 参数列表
|
||||
* @return 签名
|
||||
*/
|
||||
public static String createSign(Map<String, ?> paramsMap) {
|
||||
return SaSignManager.getSaSignTemplate().createSign(paramsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数
|
||||
* @param paramsMap 参数列表
|
||||
* @return 加工后的参数列表
|
||||
*/
|
||||
public static Map<String, Object> addSignParams(Map<String, Object> paramsMap) {
|
||||
return SaSignManager.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 SaSignManager.getSaSignTemplate().addSignParamsAndJoin(paramsMap);
|
||||
}
|
||||
|
||||
|
||||
// ----------- 校验签名
|
||||
|
||||
/**
|
||||
* 判断:指定时间戳与当前时间戳的差距是否在允许的范围内
|
||||
* @param timestamp 待校验的时间戳
|
||||
* @return 是否在允许的范围内
|
||||
*/
|
||||
public static boolean isValidTimestamp(long timestamp) {
|
||||
return SaSignManager.getSaSignTemplate().isValidTimestamp(timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:指定时间戳与当前时间戳的差距是否在允许的范围内,如果超出则抛出异常
|
||||
* @param timestamp 待校验的时间戳
|
||||
*/
|
||||
public static void checkTimestamp(long timestamp) {
|
||||
SaSignManager.getSaSignTemplate().checkTimestamp(timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:随机字符串 nonce 是否有效。
|
||||
* 注意:同一 nonce 可以被多次判断有效,不会被缓存
|
||||
* @param nonce 待判断的随机字符串
|
||||
* @return 是否有效
|
||||
*/
|
||||
public static boolean isValidNonce(String nonce) {
|
||||
return SaSignManager.getSaSignTemplate().isValidNonce(nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:随机字符串 nonce 是否有效,如果无效则抛出异常。
|
||||
* 注意:同一 nonce 只可以被校验通过一次,校验后将保存在缓存中,再次校验将无法通过
|
||||
* @param nonce 待校验的随机字符串
|
||||
*/
|
||||
public static void checkNonce(String nonce) {
|
||||
SaSignManager.getSaSignTemplate().checkNonce(nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:给定的参数 生成的签名是否为有效签名
|
||||
* @param paramsMap 参数列表
|
||||
* @param sign 待验证的签名
|
||||
* @return 签名是否有效
|
||||
*/
|
||||
public static boolean isValidSign(Map<String, ?> paramsMap, String sign) {
|
||||
return SaSignManager.getSaSignTemplate().isValidSign(paramsMap, sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:给定的参数 生成的签名是否为有效签名,如果签名无效则抛出异常
|
||||
* @param paramsMap 参数列表
|
||||
* @param sign 待验证的签名
|
||||
*/
|
||||
public static void checkSign(Map<String, ?> paramsMap, String sign) {
|
||||
SaSignManager.getSaSignTemplate().checkSign(paramsMap, sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:参数列表中的 nonce、timestamp、sign 是否均为合法的
|
||||
* @param paramMap 待校验的请求参数集合
|
||||
* @return 是否合法
|
||||
*/
|
||||
public static boolean isValidParamMap(Map<String, String> paramMap) {
|
||||
return SaSignManager.getSaSignTemplate().isValidParamMap(paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:参数列表中的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
|
||||
* @param paramMap 待校验的请求参数集合
|
||||
*/
|
||||
public static void checkParamMap(Map<String, String> paramMap) {
|
||||
SaSignManager.getSaSignTemplate().checkParamMap(paramMap);
|
||||
}
|
||||
|
||||
|
||||
// ----------- Web 请求相关 封装
|
||||
|
||||
/**
|
||||
* 判断:一个请求中的 nonce、timestamp、sign 是否均为合法的
|
||||
* @param request 待校验的请求对象
|
||||
* @param paramNames 指定参与签名的参数有哪些,如果不填写则默认为全部参数
|
||||
* @return 是否合法
|
||||
*/
|
||||
public static boolean isValidRequest(SaRequest request, String... paramNames) {
|
||||
return SaSignManager.getSaSignTemplate().isValidRequest(request, paramNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:一个请求的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
|
||||
* @param request 待校验的请求对象
|
||||
* @param paramNames 指定参与签名的参数有哪些,如果不填写则默认为全部参数
|
||||
*/
|
||||
public static void checkRequest(SaRequest request, String... paramNames) {
|
||||
SaSignManager.getSaSignTemplate().checkRequest(request, paramNames);
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
cn.dev33.satoken.plugin.SaTokenPluginForSign
|
||||
@@ -22,6 +22,11 @@
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-core</artifactId>
|
||||
</dependency>
|
||||
<!-- sa-token-sign -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-sign</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
+4
-3
@@ -16,8 +16,9 @@
|
||||
package cn.dev33.satoken.sso.template;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaSignConfig;
|
||||
import cn.dev33.satoken.sign.SaSignTemplate;
|
||||
import cn.dev33.satoken.sign.SaSignManager;
|
||||
import cn.dev33.satoken.sign.config.SaSignConfig;
|
||||
import cn.dev33.satoken.sign.template.SaSignTemplate;
|
||||
import cn.dev33.satoken.sso.SaSsoManager;
|
||||
import cn.dev33.satoken.sso.config.SaSsoClientConfig;
|
||||
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
|
||||
@@ -246,7 +247,7 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
|
||||
* @return /
|
||||
*/
|
||||
public SaSignTemplate getSignTemplate() {
|
||||
SaSignConfig signConfig = SaManager.getSaSignTemplate().getSignConfigOrGlobal().copy();
|
||||
SaSignConfig signConfig = SaSignManager.getSaSignTemplate().getSignConfigOrGlobal().copy();
|
||||
|
||||
// 使用 secretKey 的优先级:SSO 模块全局配置 > sign 模块默认配置
|
||||
String secretKey = getClientConfig().getSecretKey();
|
||||
|
||||
+5
-4
@@ -16,9 +16,10 @@
|
||||
package cn.dev33.satoken.sso.template;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaSignConfig;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.sign.SaSignTemplate;
|
||||
import cn.dev33.satoken.sign.SaSignManager;
|
||||
import cn.dev33.satoken.sign.config.SaSignConfig;
|
||||
import cn.dev33.satoken.sign.template.SaSignTemplate;
|
||||
import cn.dev33.satoken.sso.SaSsoManager;
|
||||
import cn.dev33.satoken.sso.config.SaSsoClientModel;
|
||||
import cn.dev33.satoken.sso.config.SaSsoServerConfig;
|
||||
@@ -327,7 +328,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
scm.setIsSlo(serverConfig.getIsSlo());
|
||||
scm.setSecretKey(serverConfig.getSecretKey());
|
||||
if(SaFoxUtil.isEmpty(scm.getSecretKey())) {
|
||||
scm.setSecretKey(SaManager.getSaSignTemplate().getSignConfigOrGlobal().getSecretKey());
|
||||
scm.setSecretKey(SaSignManager.getSaSignTemplate().getSignConfigOrGlobal().getSecretKey());
|
||||
}
|
||||
return scm;
|
||||
}
|
||||
@@ -781,7 +782,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
* @return /
|
||||
*/
|
||||
public SaSignTemplate getSignTemplate(String client) {
|
||||
SaSignConfig signConfig = SaManager.getSaSignTemplate().getSignConfigOrGlobal().copy();
|
||||
SaSignConfig signConfig = SaSignManager.getSaSignTemplate().getSignConfigOrGlobal().copy();
|
||||
SaSsoClientModel clientModel = getClientNotNull(client);
|
||||
|
||||
// 使用 secretKey 的优先级:client 单独配置 > SSO 模块全局配置 > sign 模块默认配置
|
||||
|
||||
Reference in New Issue
Block a user