新增 getData 接口配置,在模式三拉取数据时可以传递任意参数

This commit is contained in:
click33
2023-05-02 03:22:37 +08:00
parent 3a84c3d51e
commit aa2663e3f5
21 changed files with 668 additions and 258 deletions

View File

@@ -61,31 +61,36 @@ public class SaSsoConfig implements Serializable {
*/
public String authUrl = "/sso/auth";
/**
* 是否打开单点注销功能
*/
// public Boolean isSlo = true; // 同Server端
// /**
// * 是否打开单点注销功能
// */
// public Boolean isSlo = true; // 同Server端,不再重复声明
/**
* 是否打开模式三(此值为 true 时将使用 http 请求校验ticket值、单点注销、获取userinfo
*/
// public Boolean isHttp = false; // 同Server端
// /**
// * 是否打开模式三(此值为 true 时将使用 http 请求校验ticket值、单点注销、获取userinfo
// */
// public Boolean isHttp = false; // 同Server端,不再重复声明
/**
* 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
*/
// public String secretkey; // 同Server端
// /**
// * 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
// */
// public String secretkey; // 同Server端,不再重复声明
/**
* 配置 Server 端的 ticket 校验地址
*/
public String checkTicketUrl = "/sso/checkTicket";
/**
* 配置 Server 端查询数据 getData 地址
*/
public String getDataUrl = "/sso/getData";
/**
* 配置 Server 端查询 userinfo 地址
*/
public String userinfoUrl = "/sso/userinfo";
/**
* 配置 Server 端单点注销地址
*/
@@ -97,7 +102,7 @@ public class SaSsoConfig implements Serializable {
public String ssoLogoutCall;
/**
* 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置
* 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、getDataUrl、sloUrl 属性前面,用以简化各种 url 配置
*/
public String serverUrl;
@@ -240,6 +245,22 @@ public class SaSsoConfig implements Serializable {
return this;
}
/**
* @return Server 端查询数据 getData 地址
*/
public String getGetDataUrl() {
return getDataUrl;
}
/**
* @param getDataUrl 配置 Server 端查询数据 getData 地址
* @return 对象自身
*/
public SaSsoConfig setGetDataUrl(String getDataUrl) {
this.getDataUrl = getDataUrl;
return this;
}
/**
* @return 配置的 Server 端查询 userinfo 地址
*/
@@ -289,14 +310,14 @@ public class SaSsoConfig implements Serializable {
}
/**
* @return 配置的 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置
* @return 配置的 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、getDataUrl、sloUrl 属性前面,用以简化各种 url 配置
*/
public String getServerUrl() {
return serverUrl;
}
/**
* @param serverUrl 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置
* @param serverUrl 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、getDataUrl、sloUrl 属性前面,用以简化各种 url 配置
* @return 对象自身
*/
public SaSsoConfig setServerUrl(String serverUrl) {
@@ -331,6 +352,7 @@ public class SaSsoConfig implements Serializable {
+ ", client=" + client
+ ", authUrl=" + authUrl
+ ", checkTicketUrl=" + checkTicketUrl
+ ", getDataUrl=" + getDataUrl
+ ", userinfoUrl=" + userinfoUrl
+ ", sloUrl=" + sloUrl
+ ", ssoLogoutCall=" + ssoLogoutCall
@@ -356,6 +378,13 @@ public class SaSsoConfig implements Serializable {
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getCheckTicketUrl());
}
/**
* @return 获取拼接urlServer 端查询数据 getData 地址
*/
public String splicingGetDataUrl() {
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getGetDataUrl());
}
/**
* @return 获取拼接urlServer 端查询 userinfo 地址
*/

View File

@@ -1,12 +1,5 @@
package cn.dev33.satoken.sso;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.context.model.SaRequest;
@@ -21,6 +14,8 @@ import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult;
import java.util.*;
/**
* Sa-Token-SSO 单点登录模块
* @author kong
@@ -153,7 +148,7 @@ public class SaSsoTemplate {
}
String loginId = SaManager.getSaTokenDao().get(splicingTicketSaveKey(ticket));
// 如果是 "a,b" 的格式,则只取最前面的一项
if(loginId != null && loginId.indexOf(",") > -1) {
if(loginId != null && loginId.contains(",")) {
String[] arr = loginId.split(",");
loginId = arr[0];
}
@@ -206,7 +201,7 @@ public class SaSsoTemplate {
// 如果是 "a,b" 的格式,则解析出对应的 Client
String ticketClient = null;
if(loginId.indexOf(",") > -1) {
if(loginId.contains(",")) {
String[] arr = loginId.split(",");
loginId = arr[0];
ticketClient = arr[1];
@@ -252,7 +247,7 @@ public class SaSsoTemplate {
public void checkRedirectUrl(String url) {
// 1、是否是一个有效的url
if(SaFoxUtil.isUrl(url) == false) {
if( ! SaFoxUtil.isUrl(url) ) {
throw new SaSsoException("无效redirect" + url).setCode(SaSsoErrorCode.CODE_30001);
}
@@ -264,12 +259,11 @@ public class SaSsoTemplate {
// 3、是否在[允许地址列表]之中
List<String> authUrlList = Arrays.asList(getAllowUrl().replaceAll(" ", "").split(","));
if(SaStrategy.me.hasElement.apply(authUrlList, url) == false) {
if( ! SaStrategy.me.hasElement.apply(authUrlList, url) ) {
throw new SaSsoException("非法redirect" + url).setCode(SaSsoErrorCode.CODE_30002);
}
// 校验通过 √
return;
// 校验通过 √
}
@@ -285,7 +279,7 @@ public class SaSsoTemplate {
return;
}
SaSession session = getStpLogic().getSessionByLoginId(loginId);
Set<String> urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, ()-> new HashSet<String>());
Set<String> urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, HashSet::new);
urlSet.add(sloCallbackUrl);
session.set(SaSsoConsts.SLO_CALLBACK_SET_KEY, urlSet);
}
@@ -304,7 +298,7 @@ public class SaSsoTemplate {
// step.1 遍历通知 Client 端注销会话
SaSsoConfig cfg = SaSsoManager.getConfig();
Set<String> urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, () -> new HashSet<String>());
Set<String> urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, HashSet::new);
for (String url : urlSet) {
url = addSignParams(url, loginId);
cfg.getSendHttp().apply(url);
@@ -315,12 +309,23 @@ public class SaSsoTemplate {
}
/**
* 获取:账号资料
* @param loginId 账号id
* @return 账号资料
* 根据配置的 getData 地址,查询数据
* @param paramMap 查询参数
* @return 查询结果
*/
public Object getUserinfo(Object loginId) {
String url = buildUserinfoUrl(loginId);
public Object getData(Map<String, Object> paramMap) {
String getDataUrl = SaSsoManager.getConfig().splicingGetDataUrl();
return getData(getDataUrl, paramMap);
}
/**
* 根据自定义 path 地址,查询数据 (此方法需要配置 sa-token.sso.server-url 地址)
* @param path 自定义 path
* @param paramMap 查询参数
* @return 查询结果
*/
public Object getData(String path, Map<String, Object> paramMap) {
String url = buildCustomPathUrl(path, paramMap);
return SaSsoManager.getConfig().getSendHttp().apply(url);
}
@@ -355,17 +360,16 @@ public class SaSsoTemplate {
* 部分 Servlet 版本 request.getRequestURL() 返回的 url 带有 query 参数形如http://domain.com?id=1
* 如果不加判断会造成最终生成的 serverAuthUrl 带有双 back 参数 ,这个 if 判断正是为了解决此问题
*/
if(clientLoginUrl.indexOf(paramName.back + "=" + back) == -1) {
if( ! clientLoginUrl.contains(paramName.back + "=" + back) ) {
clientLoginUrl = SaFoxUtil.joinParam(clientLoginUrl, paramName.back, back);
}
String serverAuthUrl = SaFoxUtil.joinParam(serverUrl, paramName.redirect, clientLoginUrl);
// 返回
return serverAuthUrl;
return SaFoxUtil.joinParam(serverUrl, paramName.redirect, clientLoginUrl);
}
/**
* 构建URLServer端向Client下放ticke的地址
* 构建URLServer端向Client下放ticket的地址
* @param loginId 账号id
* @param client 客户端标识
* @param redirect Client端提供的重定向地址
@@ -412,16 +416,6 @@ public class SaSsoTemplate {
return url;
}
/**
* 构建URLServer端 账号资料查询地址
* @param loginId 账号id
* @return Server端 账号资料查询地址
*/
public String buildUserinfoUrl(Object loginId) {
String userinfoUrl = SaSsoManager.getConfig().splicingUserinfoUrl();
return addSignParams(userinfoUrl, loginId);
}
/**
* 构建URL校验ticket的URL
* <p> 在模式三下Client端拿到Ticket后根据此地址向Server端发送请求获取账号id
@@ -461,6 +455,34 @@ public class SaSsoTemplate {
return addSignParams(url, loginId);
}
/**
* 构建URLServer端 getData 地址,带签名等参数
* @param paramMap 查询参数
* @return /
*/
public String buildGetDataUrl(Map<String, Object> paramMap) {
String getDataUrl = SaSsoManager.getConfig().getGetDataUrl();
return buildCustomPathUrl(getDataUrl, paramMap);
}
/**
* 构建URLServer 端自定义 path 地址,带签名等参数 (此方法需要配置 sa-token.sso.server-url 地址)
* @param paramMap 请求参数
* @return /
*/
public String buildCustomPathUrl(String path, Map<String, Object> paramMap) {
// 如果path不是以 http 开头,那么就拼接上 serverUrl
String url = path;
if( ! url.startsWith("http") ) {
String serverUrl = SaSsoManager.getConfig().getServerUrl();
SaSsoException.throwByNull(serverUrl, "请先配置 sa-token.sso.server-url 地址", SaSsoErrorCode.CODE_30012);
url = SaFoxUtil.spliceTwoUrl(serverUrl, path);
}
// 添加签名等参数,并序列化
return addSignParams(url, paramMap);
}
// ------------------- 返回相应key -------------------
@@ -510,24 +532,65 @@ public class SaSsoTemplate {
}
/**
* 校验secretkey秘钥是否有效 API已过期请更改为更安全的 sign 式校验)
* @param secretkey 秘钥
* 给 paramMap 追加 sign 等参数并序列化为kv字符串拼接到url后面
* @param url 请求地址
* @param paramMap 请求原始参数列表
* @return 加工后的url
*/
@Deprecated
public void checkSecretkey(String secretkey) {
if(SaFoxUtil.isEmpty(secretkey) || secretkey.equals(getSecretkey()) == false) {
throw new SaSsoException("无效秘钥:" + secretkey).setCode(SaSsoErrorCode.CODE_30003);
}
public String addSignParams(String url, Map<String, Object> paramMap) {
// 追加:时间戳、随机字符串、参数签名
SaManager.getSaSignTemplate().addSignParams(paramMap, getSecretkey());
// 序列化为kv字符串
String signParams = SaManager.getSaSignTemplate().joinParams(paramMap);
// 拼接到一起
return SaFoxUtil.joinParam(url, signParams);
}
/**
* 根据参数计算签名
* 给 url 拼接 loginId 参数,并拼接 sign 等参数
* @param url 链接
* @param loginId 账号id
* @return 加工后的url
*/
public String addSignParams(String url, Object loginId) {
Map<String, Object> paramMap = new LinkedHashMap<>();
paramMap.put(paramName.loginId, loginId);
return addSignParams(url, paramMap);
}
/**
* 校验签名
* @param req request
*/
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);
}
// -------- 以下方法已废弃,仅为兼容旧版本而保留 --------
/**
* 根据参数计算签名
* @param loginId 账号id
* @param timestamp 当前时间戳13位
* @param nonce 随机字符串
* @param nonce 随机字符串
* @param secretkey 账号id
* @return 签名
* @return 签名
*/
@Deprecated
public String getSign(Object loginId, String timestamp, String nonce, String secretkey) {
Map<String, Object> map = new TreeMap<>();
map.put(paramName.loginId, loginId);
@@ -537,58 +600,26 @@ public class SaSsoTemplate {
}
/**
* 给 url 追加 sign 等参数
* @param url 连接
* @param loginId 账号id
* @return 加工后的url
* 构建URLServer端 账号资料查询地址
* @param loginId 账号id
* @return Server端 账号资料查询地址
*/
public String addSignParams(String url, Object loginId) {
// 时间戳、随机字符串、参数签名
String timestamp = String.valueOf(System.currentTimeMillis());
String nonce = SaFoxUtil.getRandomString(20);
String sign = getSign(loginId, timestamp, nonce, getSecretkey());
// 追加到url
url = SaFoxUtil.joinParam(url, paramName.loginId, loginId);
url = SaFoxUtil.joinParam(url, paramName.timestamp, timestamp);
url = SaFoxUtil.joinParam(url, paramName.nonce, nonce);
url = SaFoxUtil.joinParam(url, paramName.sign, sign);
return url;
@Deprecated
public String buildUserinfoUrl(Object loginId) {
String userinfoUrl = SaSsoManager.getConfig().splicingUserinfoUrl();
return addSignParams(userinfoUrl, loginId);
}
/**
* 校验签名
* @param req request
* 获取:账号资料
* @param loginId 账号id
* @return 账号资料
*/
public void checkSign(SaRequest req) {
// 参数签名、账号id、时间戳、随机字符串
String sign = req.getParamNotNull(paramName.sign);
String loginId = req.getParamNotNull(paramName.loginId);
String timestamp = req.getParamNotNull(paramName.timestamp);
String nonce = req.getParamNotNull(paramName.nonce);
// 校验时间戳
checkTimestamp(Long.valueOf(timestamp));
// 校验签名
String calcSign = getSign(loginId, timestamp, nonce, getSecretkey());
if(calcSign.equals(sign) == false) {
throw new SaSsoException("签名无效:" + calcSign).setCode(SaSsoErrorCode.CODE_30008);
}
@Deprecated
public Object getUserinfo(Object loginId) {
String url = buildUserinfoUrl(loginId);
return SaSsoManager.getConfig().getSendHttp().apply(url);
}
/**
* 校验时间戳与当前时间的差距是否超出限制
* @param timestamp 时间戳
*/
public void checkTimestamp(long timestamp) {
long disparity = Math.abs(System.currentTimeMillis() - timestamp);
long allowDisparity = SaSsoManager.getConfig().getTimestampDisparity();
if(allowDisparity != -1 && disparity > allowDisparity) {
throw new SaSsoException("timestamp 超出允许的范围").setCode(SaSsoErrorCode.CODE_30007);
}
}
}

View File

@@ -3,6 +3,8 @@ package cn.dev33.satoken.sso;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.util.SaResult;
import java.util.Map;
/**
* Sa-Token-SSO 单点登录模块 工具类
* @author kong
@@ -139,12 +141,22 @@ public class SaSsoUtil {
}
/**
* 获取:账号资料
* @param loginId 账号id
* @return 账号资料
* 获取:查询数据
* @param paramMap 查询参数
* @return 查询结果
*/
public static Object getUserinfo(Object loginId) {
return ssoTemplate.getUserinfo(loginId);
public static Object getData(Map<String, Object> paramMap) {
return ssoTemplate.getData(paramMap);
}
/**
* 根据自定义 path 查询数据 (此方法需要配置 sa-token.sso.server-url 地址)
* @param path 自定义 path
* @param paramMap 查询参数
* @return 查询结果
*/
public static Object getData(String path, Map<String, Object> paramMap) {
return ssoTemplate.getData(path, paramMap);
}
@@ -161,7 +173,7 @@ public class SaSsoUtil {
}
/**
* 构建URLServer端向Client下放ticke的地址
* 构建URLServer端向Client下放ticket的地址
* @param loginId 账号id
* @param client 客户端标识
* @param redirect Client端提供的重定向地址
@@ -172,14 +184,23 @@ public class SaSsoUtil {
}
/**
* 构建URLServer端 账号资料查询地址
* @param loginId 账号id
* @return Server端 账号资料查询地址
* 构建URLServer端 getData 地址,带签名等参数
* @param paramMap 查询参数
* @return /
*/
public static String buildUserinfoUrl(Object loginId) {
return ssoTemplate.buildUserinfoUrl(loginId);
public static String buildGetDataUrl(Map<String, Object> paramMap) {
return ssoTemplate.buildGetDataUrl(paramMap);
}
/**
* 构建URLServer 端自定义 path 地址,带签名等参数 (此方法需要配置 sa-token.sso.server-url 地址)
* @param paramMap 请求参数
* @return /
*/
public static String buildCustomPathUrl(String path, Map<String, Object> paramMap) {
return ssoTemplate.buildCustomPathUrl(path, paramMap);
}
// ------------------- 请求相关 -------------------
@@ -193,31 +214,20 @@ public class SaSsoUtil {
}
/**
* 校验secretkey秘钥是否有效 API已过期请更改为更安全的 sign 式校验)
* @param secretkey 秘钥
* 给 paramMap 追加 sign 等参数并序列化为kv字符串拼接到url后面
* @param url 请求地址
* @param paramMap 请求原始参数列表
* @return 加工后的url
*/
@Deprecated
public static void checkSecretkey(String secretkey) {
ssoTemplate.checkSecretkey(secretkey);
public static String addSignParams(String url, Map<String, Object> paramMap) {
return ssoTemplate.addSignParams(url, paramMap);
}
/**
* 根据参数计算签名
* 给 url 拼接 loginId 参数,并拼接 sign 等参数
* @param url 链接
* @param loginId 账号id
* @param timestamp 当前时间戳13位
* @param nonce 随机字符串
* @param secretkey 账号id
* @return 签名
*/
public static String getSign(Object loginId, String timestamp, String nonce, String secretkey) {
return ssoTemplate.getSign(loginId, timestamp, nonce, secretkey);
}
/**
* 给 url 追加 sign 等参数
* @param url 连接
* @param loginId 账号id
* @return 加工后的url
* @return 加工后的url
*/
public static String addSignParams(String url, Object loginId) {
return ssoTemplate.addSignParams(url, loginId);
@@ -231,12 +241,40 @@ public class SaSsoUtil {
ssoTemplate.checkSign(req);
}
// -------- 以下方法已废弃,仅为兼容旧版本而保留 --------
/**
* 校验时间戳与当前时间的差距是否超出限制
* @param timestamp 时间戳
* 根据参数计算签名
* @param loginId 账号id
* @param timestamp 当前时间戳13位
* @param nonce 随机字符串
* @param secretkey 账号id
* @return 签名
*/
public static void checkTimestamp(long timestamp) {
ssoTemplate.checkTimestamp(timestamp);
@Deprecated
public static String getSign(Object loginId, String timestamp, String nonce, String secretkey) {
return ssoTemplate.getSign(loginId, timestamp, nonce, secretkey);
}
/**
* 获取:账号资料
* @param loginId 账号id
* @return 账号资料
*/
@Deprecated
public static Object getUserinfo(Object loginId) {
return ssoTemplate.getUserinfo(loginId);
}
/**
* 构建URLServer端 账号资料查询地址
* @param loginId 账号id
* @return Server端 账号资料查询地址
*/
@Deprecated
public static String buildUserinfoUrl(Object loginId) {
return ssoTemplate.buildUserinfoUrl(loginId);
}
}

View File

@@ -40,5 +40,8 @@ public interface SaSsoErrorCode {
/** 该 ticket 不属于当前 client */
public static final int CODE_30011 = 30011;
/** 当前缺少配置 server-url 地址 */
public static final int CODE_30012 = 30012;
}