feat(sso): 新增 SSO Strategy 策略类

This commit is contained in:
click33
2025-05-03 12:04:14 +08:00
parent 1d9b730685
commit 6e9bb2b31a
15 changed files with 217 additions and 82 deletions

View File

@@ -2,8 +2,8 @@ package com.pj.sso;
import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.sign.SaSignUtil; import cn.dev33.satoken.sign.SaSignUtil;
import cn.dev33.satoken.sso.config.SaSsoServerConfig;
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor; import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaFoxUtil;
@@ -35,15 +35,15 @@ public class SsoServerController {
// 配置SSO相关参数 // 配置SSO相关参数
@Autowired @Autowired
private void configSso(SaSsoServerConfig ssoServer) { private void configSso(SaSsoServerTemplate ssoServerTemplate) {
// 配置未登录时返回的View // 配置未登录时返回的View
ssoServer.notLoginView = () -> { ssoServerTemplate.strategy.notLoginView = () -> {
return new ModelAndView("sa-login.html"); return new ModelAndView("sa-login.html");
}; };
// 配置:登录处理函数 // 配置:登录处理函数
ssoServer.doLoginHandle = (name, pwd) -> { ssoServerTemplate.strategy.doLoginHandle = (name, pwd) -> {
// 此处仅做模拟登录,真实环境应该查询数据进行登录 // 此处仅做模拟登录,真实环境应该查询数据进行登录
if("sa".equals(name) && "123456".equals(pwd)) { if("sa".equals(name) && "123456".equals(pwd)) {
String deviceId = SaHolder.getRequest().getParam("deviceId", SaFoxUtil.getRandomString(32)); String deviceId = SaHolder.getRequest().getParam("deviceId", SaFoxUtil.getRandomString(32));

View File

@@ -1,8 +1,8 @@
package com.pj.sso; package com.pj.sso;
import cn.dev33.satoken.sso.SaSsoManager; import cn.dev33.satoken.sso.SaSsoManager;
import cn.dev33.satoken.sso.config.SaSsoClientConfig;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor; import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult; import cn.dev33.satoken.util.SaResult;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -41,7 +41,7 @@ public class SsoClientController {
// 配置SSO相关参数 // 配置SSO相关参数
@Autowired @Autowired
private void configSso(SaSsoClientConfig ssoClient) { private void configSso(SaSsoClientTemplate ssoClientTemplate) {
} }

View File

@@ -1,7 +1,7 @@
package com.pj.sso; package com.pj.sso;
import cn.dev33.satoken.sso.config.SaSsoClientConfig;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor; import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
import cn.dev33.satoken.sso.template.SaSsoUtil; import cn.dev33.satoken.sso.template.SaSsoUtil;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult; import cn.dev33.satoken.util.SaResult;
@@ -43,7 +43,7 @@ public class SsoClientController {
// 配置SSO相关参数 // 配置SSO相关参数
@Autowired @Autowired
private void configSso(SaSsoClientConfig ssoClient) { private void configSso(SaSsoClientTemplate ssoClientTemplate) {
} }

View File

@@ -16,7 +16,6 @@
package cn.dev33.satoken.sso.config; package cn.dev33.satoken.sso.config;
import cn.dev33.satoken.sso.function.TicketResultHandleFunction;
import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaFoxUtil;
import java.io.Serializable; import java.io.Serializable;
@@ -133,16 +132,6 @@ public class SaSsoClientConfig implements Serializable {
} }
// -------------------- 所有回调函数 --------------------
/**
* SSO-Client端自定义校验 ticket 返回值的处理逻辑 (每次从认证中心获取校验 ticket 的结果后调用)
* <p> 参数loginId, back
* <p> 返回值:返回给前端的值
*/
public TicketResultHandleFunction ticketResultHandle = null;
// get set // get set
/** /**

View File

@@ -16,12 +16,8 @@
package cn.dev33.satoken.sso.config; package cn.dev33.satoken.sso.config;
import cn.dev33.satoken.sso.function.CheckTicketAppendDataFunction;
import cn.dev33.satoken.sso.function.DoLoginHandleFunction;
import cn.dev33.satoken.sso.function.NotLoginViewFunction;
import cn.dev33.satoken.sso.template.SaSsoServerTemplate; import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult;
import java.io.Serializable; import java.io.Serializable;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -122,31 +118,6 @@ public class SaSsoServerConfig implements Serializable {
} }
// -------------------- 所有回调函数 --------------------
/**
* SSO-Server端未登录时返回的View
*/
public NotLoginViewFunction notLoginView = () -> {
return "当前会话在SSO-Server认证中心尚未登录当前未配置登录视图";
};
/**
* SSO-Server端登录函数
*/
public DoLoginHandleFunction doLoginHandle = (name, pwd) -> {
return SaResult.error();
};
/**
* SSO-Server端在校验 ticket 后,给 sso-client 端追加返回信息的函数
*/
public CheckTicketAppendDataFunction checkTicketAppendData = (loginId, result) -> {
return result;
};
// get set // get set
/** /**
@@ -363,5 +334,4 @@ public class SaSsoServerConfig implements Serializable {
+ "]"; + "]";
} }
} }

View File

@@ -94,7 +94,7 @@ public class SaSsoMessageCheckTicketHandle implements SaSsoMessageHandle {
result.set(paramName.remainTokenTimeout, stpLogic.getTokenTimeout(ticketModel.getTokenValue())); result.set(paramName.remainTokenTimeout, stpLogic.getTokenTimeout(ticketModel.getTokenValue()));
result.set(paramName.remainSessionTimeout, stpLogic.getSessionTimeoutByLoginId(loginId)); result.set(paramName.remainSessionTimeout, stpLogic.getSessionTimeoutByLoginId(loginId));
result = ssoServerConfig.checkTicketAppendData.apply(loginId, result); result = ssoServerTemplate.strategy.checkTicketAppendData.apply(loginId, result);
return result; return result;
} }

View File

@@ -138,8 +138,8 @@ public class SaSsoClientProcessor {
SaCheckTicketResult ctr = checkTicket(ticket, apiName.ssoLogin); SaCheckTicketResult ctr = checkTicket(ticket, apiName.ssoLogin);
// 2、如果开发者自定义了ticket结果值处理函数则使用自定义的函数 // 2、如果开发者自定义了ticket结果值处理函数则使用自定义的函数
if(cfg.ticketResultHandle != null) { if(ssoClientTemplate.strategy.ticketResultHandle != null) {
return cfg.ticketResultHandle.run(ctr, back); return ssoClientTemplate.strategy.ticketResultHandle.run(ctr, back);
} }
// 3、登录并重定向至back地址 // 3、登录并重定向至back地址

View File

@@ -107,7 +107,7 @@ public class SaSsoServerProcessor {
// ---------- 此处有两种情况分开处理: // ---------- 此处有两种情况分开处理:
// ---- 情况1在SSO认证中心尚未登录需要先去登录 // ---- 情况1在SSO认证中心尚未登录需要先去登录
if( ! stpLogic.isLogin()) { if( ! stpLogic.isLogin()) {
return cfg.notLoginView.get(); return ssoServerTemplate.strategy.notLoginView.get();
} }
// ---- 情况2在SSO认证中心已经登录需要重定向回 Client 端,而这又分为两种方式: // ---- 情况2在SSO认证中心已经登录需要重定向回 Client 端,而这又分为两种方式:
String mode = req.getParam(paramName.mode, SaSsoConsts.MODE_TICKET); String mode = req.getParam(paramName.mode, SaSsoConsts.MODE_TICKET);
@@ -155,7 +155,7 @@ public class SaSsoServerProcessor {
ParamName paramName = ssoServerTemplate.paramName; ParamName paramName = ssoServerTemplate.paramName;
// 处理 // 处理
return cfg.doLoginHandle.apply(req.getParam(paramName.name), req.getParam(paramName.pwd)); return ssoServerTemplate.strategy.doLoginHandle.apply(req.getParam(paramName.name), req.getParam(paramName.pwd));
} }
/** /**

View File

@@ -0,0 +1,44 @@
/*
* 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.sso.strategy;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.sso.function.SendHttpFunction;
import cn.dev33.satoken.sso.function.TicketResultHandleFunction;
/**
* Sa-Token SSO Client 相关策略
*
* @author click33
* @since 1.43.0
*/
public class SaSsoClientStrategy {
/**
* 发送 Http 请求的处理函数
*/
public SendHttpFunction sendHttp = url -> {
return SaManager.getSaHttpTemplate().get(url);
};
/**
* SSO-Client端自定义校验 ticket 返回值的处理逻辑 (每次从认证中心获取校验 ticket 的结果后调用)
* <p> 参数loginId, back
* <p> 返回值:返回给前端的值
*/
public TicketResultHandleFunction ticketResultHandle = null;
}

View File

@@ -0,0 +1,61 @@
/*
* 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.sso.strategy;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.sso.function.CheckTicketAppendDataFunction;
import cn.dev33.satoken.sso.function.DoLoginHandleFunction;
import cn.dev33.satoken.sso.function.NotLoginViewFunction;
import cn.dev33.satoken.sso.function.SendHttpFunction;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token SSO Server 相关策略
*
* @author click33
* @since 1.43.0
*/
public class SaSsoServerStrategy {
/**
* 发送 Http 请求的处理函数
*/
public SendHttpFunction sendHttp = url -> {
return SaManager.getSaHttpTemplate().get(url);
};
/**
* 未登录时返回的 View
*/
public NotLoginViewFunction notLoginView = () -> {
return "当前会话在 SSO-Server 认证中心尚未登录(当前未配置登录视图)";
};
/**
* SSO-Server端登录函数
*/
public DoLoginHandleFunction doLoginHandle = (name, pwd) -> {
return SaResult.error();
};
/**
* SSO-Server端在校验 ticket 后,给 sso-client 端追加返回信息的函数
*/
public CheckTicketAppendDataFunction checkTicketAppendData = (loginId, result) -> {
return result;
};
}

View File

@@ -24,6 +24,7 @@ import cn.dev33.satoken.sso.error.SaSsoErrorCode;
import cn.dev33.satoken.sso.exception.SaSsoException; import cn.dev33.satoken.sso.exception.SaSsoException;
import cn.dev33.satoken.sso.message.SaSsoMessage; import cn.dev33.satoken.sso.message.SaSsoMessage;
import cn.dev33.satoken.sso.message.handle.client.SaSsoMessageLogoutCallHandle; import cn.dev33.satoken.sso.message.handle.client.SaSsoMessageLogoutCallHandle;
import cn.dev33.satoken.sso.strategy.SaSsoClientStrategy;
import cn.dev33.satoken.sso.util.SaSsoConsts; import cn.dev33.satoken.sso.util.SaSsoConsts;
import cn.dev33.satoken.stp.parameter.SaLogoutParameter; import cn.dev33.satoken.stp.parameter.SaLogoutParameter;
import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaFoxUtil;
@@ -39,12 +40,16 @@ import java.util.Map;
*/ */
public class SaSsoClientTemplate extends SaSsoTemplate { public class SaSsoClientTemplate extends SaSsoTemplate {
/**
* Client 相关策略
*/
public SaSsoClientStrategy strategy = new SaSsoClientStrategy();
public SaSsoClientTemplate() { public SaSsoClientTemplate() {
super.messageHolder.addHandle(new SaSsoMessageLogoutCallHandle()); super.messageHolder.addHandle(new SaSsoMessageLogoutCallHandle());
} }
// ------------------- SSO 模式三相关 ------------------- // ------------------- SSO 模式三相关 -------------------
/** /**
@@ -65,7 +70,7 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
*/ */
public Object getData(String path, Map<String, Object> paramMap) { public Object getData(String path, Map<String, Object> paramMap) {
String url = buildCustomPathUrl(path, paramMap); String url = buildCustomPathUrl(path, paramMap);
return request(url); return strategy.sendHttp.apply(url);
} }
// ---------------------- 构建URL ---------------------- // ---------------------- 构建URL ----------------------
@@ -88,7 +93,6 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
serverUrl = SaFoxUtil.joinParam(serverUrl, paramName.client, client); serverUrl = SaFoxUtil.joinParam(serverUrl, paramName.client, client);
} }
// 对back地址编码 // 对back地址编码
back = (back == null ? "" : back); back = (back == null ? "" : back);
back = SaFoxUtil.encodeUrl(back); back = SaFoxUtil.encodeUrl(back);
@@ -179,6 +183,18 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
// ------------------- 消息推送 ------------------- // ------------------- 消息推送 -------------------
/**
* 发送 Http 请求,并将响应结果转换为 SaResult
*
* @param url 请求地址
* @return 返回的结果
*/
public SaResult requestAsSaResult(String url) {
String body = strategy.sendHttp.apply(url);
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(body);
return new SaResult(map);
}
/** /**
* 向 sso-server 推送消息 * 向 sso-server 推送消息
* *
@@ -199,7 +215,7 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
// 发起请求 // 发起请求
String finalUrl = SaFoxUtil.joinParam(pushUrl, paramsStr); String finalUrl = SaFoxUtil.joinParam(pushUrl, paramsStr);
return request(finalUrl); return strategy.sendHttp.apply(finalUrl);
} }
/** /**

View File

@@ -29,6 +29,7 @@ import cn.dev33.satoken.sso.message.handle.server.SaSsoMessageCheckTicketHandle;
import cn.dev33.satoken.sso.message.handle.server.SaSsoMessageSignoutHandle; import cn.dev33.satoken.sso.message.handle.server.SaSsoMessageSignoutHandle;
import cn.dev33.satoken.sso.model.SaSsoClientInfo; import cn.dev33.satoken.sso.model.SaSsoClientInfo;
import cn.dev33.satoken.sso.model.TicketModel; import cn.dev33.satoken.sso.model.TicketModel;
import cn.dev33.satoken.sso.strategy.SaSsoServerStrategy;
import cn.dev33.satoken.sso.util.SaSsoConsts; import cn.dev33.satoken.sso.util.SaSsoConsts;
import cn.dev33.satoken.stp.parameter.SaLogoutParameter; import cn.dev33.satoken.stp.parameter.SaLogoutParameter;
import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.strategy.SaStrategy;
@@ -45,6 +46,11 @@ import java.util.*;
*/ */
public class SaSsoServerTemplate extends SaSsoTemplate { public class SaSsoServerTemplate extends SaSsoTemplate {
/**
* Server 相关策略
*/
public SaSsoServerStrategy strategy = new SaSsoServerStrategy();
public SaSsoServerTemplate() { public SaSsoServerTemplate() {
super.messageHolder.addHandle(new SaSsoMessageCheckTicketHandle()); super.messageHolder.addHandle(new SaSsoMessageCheckTicketHandle());
super.messageHolder.addHandle(new SaSsoMessageSignoutHandle()); super.messageHolder.addHandle(new SaSsoMessageSignoutHandle());
@@ -634,12 +640,24 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
String finalUrl = SaFoxUtil.joinParam(sloCallUrl, signParamsStr); String finalUrl = SaFoxUtil.joinParam(sloCallUrl, signParamsStr);
// 发起请求 // 发起请求
request(finalUrl); strategy.sendHttp.apply(finalUrl);
} }
// ------------------- 消息推送 ------------------- // ------------------- 消息推送 -------------------
/**
* 发送 Http 请求,并将响应结果转换为 SaResult
*
* @param url 请求地址
* @return 返回的结果
*/
public SaResult requestAsSaResult(String url) {
String body = strategy.sendHttp.apply(url);;
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(body);
return new SaResult(map);
}
/** /**
* 向指定 Client 推送消息 * 向指定 Client 推送消息
* @param clientModel / * @param clientModel /
@@ -651,7 +669,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
String noticeUrl = clientModel.splicingNoticeUrl(); String noticeUrl = clientModel.splicingNoticeUrl();
String paramsStr = getSignTemplate(clientModel.getClient()).addSignParamsAndJoin(message); String paramsStr = getSignTemplate(clientModel.getClient()).addSignParamsAndJoin(message);
String finalUrl = SaFoxUtil.joinParam(noticeUrl, paramsStr); String finalUrl = SaFoxUtil.joinParam(noticeUrl, paramsStr);
return request(finalUrl); return strategy.sendHttp.apply(finalUrl);
} }
/** /**

View File

@@ -76,27 +76,15 @@ public class SaSsoTemplate {
public SaSsoMessageHolder messageHolder = new SaSsoMessageHolder(); public SaSsoMessageHolder messageHolder = new SaSsoMessageHolder();
/** // /**
* 发送 Http 请求 // * 发送 Http 请求
* // *
* @param url / // * @param url /
* @return / // * @return /
*/ // */
public String request(String url) { // public String request(String url) {
return SaManager.getSaHttpTemplate().get(url); // return SaManager.getSaHttpTemplate().get(url);
} // }
/**
* 发送 Http 请求,并将响应结果转换为 SaResult
*
* @param url 请求地址
* @return 返回的结果
*/
public SaResult requestAsSaResult(String url) {
String body = request(url);
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(body);
return new SaResult(map);
}
/** /**
* 处理指定消息 * 处理指定消息

View File

@@ -18,6 +18,10 @@ package cn.dev33.satoken.solon.sso;
import cn.dev33.satoken.sso.SaSsoManager; import cn.dev33.satoken.sso.SaSsoManager;
import cn.dev33.satoken.sso.config.SaSsoClientConfig; import cn.dev33.satoken.sso.config.SaSsoClientConfig;
import cn.dev33.satoken.sso.config.SaSsoServerConfig; import cn.dev33.satoken.sso.config.SaSsoServerConfig;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
import org.noear.solon.annotation.Bean; import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Condition; import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration; import org.noear.solon.annotation.Configuration;
@@ -60,4 +64,25 @@ public class SaSsoBeanRegister {
return clientConfig; return clientConfig;
} }
} }
/**
* 获取 SSO Server 端 SaSsoServerTemplate
*
* @return /
*/
@Bean
public SaSsoServerTemplate getSaSsoServerTemplate() {
return SaSsoServerProcessor.instance.ssoServerTemplate;
}
/**
* 获取 SSO Client 端 SaSsoClientTemplate
*
* @return /
*/
@Bean
public SaSsoClientTemplate getSaSsoClientTemplate() {
return SaSsoClientProcessor.instance.ssoClientTemplate;
}
} }

View File

@@ -18,6 +18,10 @@ package cn.dev33.satoken.spring.sso;
import cn.dev33.satoken.sso.SaSsoManager; import cn.dev33.satoken.sso.SaSsoManager;
import cn.dev33.satoken.sso.config.SaSsoClientConfig; import cn.dev33.satoken.sso.config.SaSsoClientConfig;
import cn.dev33.satoken.sso.config.SaSsoServerConfig; import cn.dev33.satoken.sso.config.SaSsoServerConfig;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@@ -51,4 +55,24 @@ public class SaSsoBeanRegister {
return new SaSsoClientConfig(); return new SaSsoClientConfig();
} }
/**
* 获取 SSO Server 端 SaSsoServerTemplate
*
* @return /
*/
@Bean
public SaSsoServerTemplate getSaSsoServerTemplate() {
return SaSsoServerProcessor.instance.ssoServerTemplate;
}
/**
* 获取 SSO Client 端 SaSsoClientTemplate
*
* @return /
*/
@Bean
public SaSsoClientTemplate getSaSsoClientTemplate() {
return SaSsoClientProcessor.instance.ssoClientTemplate;
}
} }