新增不同 SSO Client 配置不同秘钥的方案

This commit is contained in:
click33
2024-05-02 07:17:11 +08:00
parent c52fd9c86f
commit 8d6b648d4b
10 changed files with 169 additions and 13 deletions

View File

@@ -37,6 +37,17 @@ public class SaSignConfig {
private long timestampDisparity = 1000 * 60 * 15; private long timestampDisparity = 1000 * 60 * 15;
public SaSignConfig() {
}
/**
* 构造函数
* @param secretKey 秘钥
*/
public SaSignConfig(String secretKey) {
this.secretKey = secretKey;
}
/** /**
* 获取 API 调用签名秘钥 * 获取 API 调用签名秘钥
* *

View File

@@ -26,6 +26,8 @@ import cn.dev33.satoken.util.SaFoxUtil;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import static cn.dev33.satoken.SaManager.log;
/** /**
* API 参数签名算法,在跨系统接口调用时防参数篡改、防重放攻击。 * API 参数签名算法,在跨系统接口调用时防参数篡改、防重放攻击。
* *
@@ -42,6 +44,17 @@ import java.util.TreeMap;
*/ */
public class SaSignTemplate { public class SaSignTemplate {
public SaSignTemplate() {
}
/**
* 构造函数
* @param signConfig 签名参数配置对象
*/
public SaSignTemplate(SaSignConfig signConfig) {
this.signConfig = signConfig;
}
// ----------- 签名配置 // ----------- 签名配置
SaSignConfig signConfig; SaSignConfig signConfig;
@@ -160,7 +173,14 @@ public class SaSignTemplate {
// 计算签名 // 计算签名
String paramsStr = joinParamsDictSort(paramsMap); String paramsStr = joinParamsDictSort(paramsMap);
String fullStr = paramsStr + "&" + key + "=" + secretKey; String fullStr = paramsStr + "&" + key + "=" + secretKey;
return abstractStr(fullStr); String signStr = abstractStr(fullStr);
// 输入日志,方便调试
log.debug("fullStr{}", fullStr);
log.debug("signStr{}", signStr);
// 返回
return signStr;
} }
/** /**

View File

@@ -3,7 +3,7 @@ server:
port: 9000 port: 9000
# Sa-Token 配置 # Sa-Token 配置
sa-token: sa-token:
# ------- SSO-模式一相关配置 (非模式一不需要配置) # ------- SSO-模式一相关配置 (非模式一不需要配置)
# cookie: # cookie:
# 配置 Cookie 作用域 # 配置 Cookie 作用域

View File

@@ -3,7 +3,7 @@ server:
port: 9032 port: 9032
# sa-token配置 # sa-token配置
sa-token: sa-token:
# sso-client 相关配置 # sso-client 相关配置
sso-client: sso-client:
# client 标识 # client 标识

View File

@@ -3,7 +3,7 @@ server:
port: 9003 port: 9003
# sa-token配置 # sa-token配置
sa-token: sa-token:
# sso-client 相关配置 # sso-client 相关配置
sso-client: sso-client:
# client 标识 # client 标识

View File

@@ -41,12 +41,13 @@
- [SSO模式一 共享Cookie同步会话](/sso/sso-type1) - [SSO模式一 共享Cookie同步会话](/sso/sso-type1)
- [SSO模式二 URL重定向传播会话](/sso/sso-type2) - [SSO模式二 URL重定向传播会话](/sso/sso-type2)
- [SSO模式三 Http请求获取会话](/sso/sso-type3) - [SSO模式三 Http请求获取会话](/sso/sso-type3)
- [SSO整合配置域名校验](/sso/sso-check-domain) - [配置域名校验](/sso/sso-check-domain)
- [SSO整合定制化登录页面](/sso/sso-custom-login) - [定制化登录页面](/sso/sso-custom-login)
- [SSO整合自定义API路由](/sso/sso-custom-api) - [自定义API路由](/sso/sso-custom-api)
- [SSO扩展前后端分离下的整合方案](/sso/sso-h5) - [前后端分离下的整合方案](/sso/sso-h5)
- [SSO扩展平台中心跳转模式](/sso/sso-home-jump) - [平台中心跳转模式](/sso/sso-home-jump)
- [SSO扩展常见问题总结](/sso/sso-questions) - [不同 Client 不同秘钥](/sso/sso-diff-key)
- [常见问题总结](/sso/sso-questions)
- [Sa-Sso-Pro单点登录商业版](/sso/sso-pro) - [Sa-Sso-Pro单点登录商业版](/sso/sso-pro)
- **OAuth2.0** - **OAuth2.0**

View File

@@ -201,8 +201,10 @@ http://{host}:{port}/sso/logoutCall
| loginId | 是 | 要注销的账号 id | | loginId | 是 | 要注销的账号 id |
| timestamp | 是 | 当前时间戳13位 | | timestamp | 是 | 当前时间戳13位 |
| nonce | 是 | 随机字符串 | | nonce | 是 | 随机字符串 |
| client | | 客户端标识,如果你在登录时向 sso-server 端传递了 client 值,那么在此处 sso-server 也会给你回传过来,否则此参数无值 | | sign | | 签名,生成算法:`md5( loginId={账号id}&nonce={随机字符串}&timestamp={13位时间戳}&key={secretkey秘钥} )` |
| sign | | 签名,生成算法:`md5( loginId={账号id}&nonce={随机字符串}&timestamp={13位时间戳}&key={secretkey秘钥} )` 如果 client 参数有值则client也要参与签名,放在 loginId 参数签名(字典顺序)| | client | | 客户端标识,如果你在登录时向 sso-server 端传递了 client 值,那么在此处 sso-server 也会给你回传过来,否则此参数无值。如果此参数有值,则此参数也要参与签名,放在 loginId 参数前面(字典顺序) |
| autoLogout | 否 | 是否为“登录client超过最大数量”引起的自动注销true=超限系统自动注销false=用户主动发起注销)。如果此参数有值,则此参数也要参与签名,放在 client 参数前面(字典顺序) |
返回数据: 返回数据:

View File

@@ -0,0 +1,119 @@
# 不同 SSO Client 配置不同秘钥
在校验 ticket、单点注销等操作发起的 http 调用时,需要配置秘钥参数,像这样:
<!---------------------------- tabs:start ---------------------------->
<!------------- tab:yaml 风格 ------------->
``` yaml
sa-token:
sign:
# API 接口调用秘钥
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
```
<!------------- tab:properties 风格 ------------->
``` properties
# 接口调用秘钥
sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
```
<!---------------------------- tabs:end ---------------------------->
如果 SSO Client 端和 SSO Server 端配置的秘钥不同,则无法调通请求,显示无效签名:
``` js
{
"code": 500,
"msg": "无效签名9f1b453817bfeac56d2f772a66c01eb2",
"data": null
}
```
如果你有多个 SSO Client你可能想让每个应用配置不同的秘钥让它们彼此之间不能互相“冒充”怎么做呢
### 1、首先在 SSO Client 端,你需要配置上不同的 Client 标识参数:
例如在 client1 我们配置上:
<!---------------------------- tabs:start ---------------------------->
<!------------- tab:yaml 风格 ------------->
``` yaml
sa-token:
sso-client:
# 当前 client 标识
client: sso-client1
# ...
sign:
# sso-client1 使用的秘钥
secret-key: secret-key-xxxx-1
```
<!------------- tab:properties 风格 ------------->
``` properties
# 当前 client 标识
sa-token.sso-client.client=sso-client1
# sso-client1 使用的秘钥
sa-token.sign.secret-key=secret-key-xxxx-1
```
<!---------------------------- tabs:end ---------------------------->
在 client2 我们配置上:
<!---------------------------- tabs:start ---------------------------->
<!------------- tab:yaml 风格 ------------->
``` yaml
sa-token:
sso-client:
# 当前 client 标识
client: sso-client2
# ...
sign:
# sso-client2 使用的秘钥
secret-key: secret-key-xxxx-2
```
<!------------- tab:properties 风格 ------------->
``` properties
# 当前 client 标识
sa-token.sso-client.client=sso-client2
# sso-client2 使用的秘钥
sa-token.sign.secret-key=secret-key-xxxx-2
```
<!---------------------------- tabs:end ---------------------------->
### 2、然后在 SSO Server 端,重写获取秘钥的函数
在 SSO Server 端新建 `CustomSaSsoServerTemplate.java`,继承 `SaSsoServerTemplate`,重写其 `getSignTemplate` 函数:
``` java
/**
* 自定义 SaSsoServerTemplate 子类
*/
@Component
public class CustomSaSsoServerTemplate extends SaSsoServerTemplate {
// 存储所有 client 的秘钥
static Map<String, SaSignTemplate> signMap = new HashMap<>();
static {
signMap.put("sso-client1", new SaSignTemplate(new SaSignConfig("secret-key-xxxx-1")));
signMap.put("sso-client2", new SaSignTemplate(new SaSignConfig("secret-key-xxxx-2")));
signMap.put("sso-client3", new SaSignTemplate(new SaSignConfig("secret-key-xxxx-3")));
// ...
}
@Override
public SaSignTemplate getSignTemplate(String client) {
// 先从自定义的 signMap 中获取
SaSignTemplate saSignTemplate = signMap.get(client);
if (saSignTemplate != null) {
return saSignTemplate;
}
// 找不到就返回全局默认的 SaSignTemplate
return SaManager.getSaSignTemplate();
}
}
```
至此完成,其它代码一切照旧。

View File

@@ -363,6 +363,9 @@ forest:
``` properties ``` properties
# 接口调用秘钥 # 接口调用秘钥
sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# 关闭 forest 请求日志打印
forest.log-enabled=false
``` ```
<!---------------------------- tabs:end ----------------------------> <!---------------------------- tabs:end ---------------------------->

View File

@@ -150,7 +150,7 @@ public class SaSsoClientProcessor {
// 无论登录时选择的是模式二还是模式三 // 无论登录时选择的是模式二还是模式三
// 在注销时都应该按照模式三的方法,通过 http 请求调用 sso-server 的单点注销接口来做到全端下线 // 在注销时都应该按照模式三的方法,通过 http 请求调用 sso-server 的单点注销接口来做到全端下线
if(cfg.getIsSlo() && ! cfg.getIsHttp()) { if(cfg.getIsSlo()) {
return ssoLogoutByMode3(); return ssoLogoutByMode3();
} }