更换单点注销接口响应格式

This commit is contained in:
click33
2022-04-27 01:53:20 +08:00
parent e320a8e45b
commit 5e3795e29e
8 changed files with 190 additions and 56 deletions

View File

@@ -279,12 +279,16 @@ public class SaSsoConfig implements Serializable {
/**
* SSO-Server端未登录时返回的View
*/
public Supplier<Object> notLoginView = () -> "当前会话在SSO-Server认证中心尚未登录";
public Supplier<Object> notLoginView = () -> {
return "当前会话在SSO-Server认证中心尚未登录";
};
/**
* SSO-Server端登录函数
*/
public BiFunction<String, String, Object> doLoginHandle = (name, pwd) -> SaResult.error();
public BiFunction<String, String, Object> doLoginHandle = (name, pwd) -> {
return SaResult.error();
};
/**
* SSO-Client端自定义校验Ticket返回值的处理逻辑 每次从认证中心获取校验Ticket的结果后调用
@@ -294,7 +298,9 @@ public class SaSsoConfig implements Serializable {
/**
* SSO-Client端发送Http请求的处理函数
*/
public Function<String, Object> sendHttp = url -> {throw new SaTokenException("请配置Http处理器");};
public Function<String, String> sendHttp = url -> {
throw new SaTokenException("请配置 Http 请求处理器");
};
/**
@@ -349,7 +355,7 @@ public class SaSsoConfig implements Serializable {
* @param sendHttp SSO-Client端发送Http请求的处理函数
* @return 对象自身
*/
public SaSsoConfig setSendHttp(Function<String, Object> sendHttp) {
public SaSsoConfig setSendHttp(Function<String, String> sendHttp) {
this.sendHttp = sendHttp;
return this;
}
@@ -357,7 +363,7 @@ public class SaSsoConfig implements Serializable {
/**
* @return 函数 SSO-Client端发送Http请求的处理函数
*/
public Function<String, Object> getSendHttp() {
public Function<String, String> getSendHttp() {
return sendHttp;
}

View File

@@ -1,5 +1,8 @@
package cn.dev33.satoken.sso;
import java.util.Map;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
@@ -19,6 +22,8 @@ import cn.dev33.satoken.util.SaResult;
*/
public class SaSsoHandle {
// ----------- SSO-Server 端路由分发
/**
* 处理Server端所有请求
* @return 处理结果
@@ -46,14 +51,14 @@ public class SaSsoHandle {
return ssoCheckTicket();
}
// SSO-Server端单点注销 [模式一] (不带loginId参数)
// SSO-Server端单点注销 [用户访问式] (不带loginId参数)
if(req.isPath(Api.ssoLogout) && cfg.getIsSlo() && req.hasParam(ParamName.loginId) == false) {
return ssoServerLogoutType1();
return ssoLogoutByUserVisit();
}
// SSO-Server端单点注销 [模式三] (带loginId参数)
// SSO-Server端单点注销 [Client调用式] (带loginId参数 & isHttp=true)
if(req.isPath(Api.ssoLogout) && cfg.getIsHttp() && cfg.getIsSlo() && req.hasParam(ParamName.loginId)) {
return ssoServerLogout();
return ssoLogoutByClientHttp();
}
// 默认返回
@@ -116,38 +121,47 @@ public class SaSsoHandle {
String ticket = req.getParam(ParamName.ticket);
String sloCallback = req.getParam(ParamName.ssoLogoutCall);
// 校验ticket获取对应的账号id
// 校验ticket获取 loginId
Object loginId = SaSsoUtil.checkTicket(ticket);
// 注册此客户端的单点注销回调URL
SaSsoUtil.registerSloCallbackUrl(loginId, sloCallback);
// 返回给Client
return loginId;
// 给 client 端响应结果
if(SaFoxUtil.isEmpty(loginId)) {
return SaResult.error("无效ticket" + ticket);
} else {
return SaResult.data(loginId);
}
}
/**
* SSO-Server端单点注销 [模式一]
* SSO-Server端单点注销 [用户访问式]
* @return 处理结果
*/
public static Object ssoServerLogoutType1() {
public static Object ssoLogoutByUserVisit() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaSsoConfig cfg = SaSsoManager.getConfig();
StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;
String loginId = req.getParam(ParamName.loginId);
// step.1 遍历 Client 端注销
SaSsoUtil.forEachSloUrl(loginId, url -> cfg.getSendHttp().apply(url));
// 开始处理
// step.2 Server 端注销
stpLogic.logout();
// 返回
// 完成
return ssoLogoutBack(req, res);
}
/**
* SSO-Server端单点注销 [模式三]
* SSO-Server端单点注销 [Client调用式]
* @return 处理结果
*/
public static Object ssoServerLogout() {
public static Object ssoLogoutByClientHttp() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaSsoConfig cfg = SaSsoManager.getConfig();
@@ -157,21 +171,22 @@ public class SaSsoHandle {
String loginId = req.getParam(ParamName.loginId);
String secretkey = req.getParam(ParamName.secretkey);
// 遍历通知Client端注销会话
// step.1 校验秘钥
SaSsoUtil.checkSecretkey(secretkey);
// step.2 遍历通知Client端注销会话
// step.2 遍历 Client 端注销
SaSsoUtil.forEachSloUrl(loginId, url -> cfg.getSendHttp().apply(url));
// step.3 Server端注销
// step.3 Server 端注销
stpLogic.logout(loginId);
// 完成
return SaSsoConsts.OK;
return SaResult.ok();
}
// ----------- SSO-Client 端路由分发
/**
* 处理Client端所有请求
* @return 处理结果
@@ -236,20 +251,21 @@ public class SaSsoHandle {
String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(SaHolder.getRequest().getUrl(), back);
return res.redirect(serverAuthUrl);
} else {
// ------- 1、校验ticket获取账号id
// ------- 1、校验ticket获取 loginId
Object loginId = checkTicket(ticket, Api.ssoLogin);
// Be: 如果开发者自定义了处理逻辑
if(cfg.getTicketResultHandle() != null) {
return cfg.getTicketResultHandle().apply(loginId, back);
}
// ------- 2、如果loginId有值说明ticket有效进行登录并重定向至back地址
if(loginId != null ) {
// ------- 2、如果 loginId 无值,说明 ticket 无效
if(SaFoxUtil.isEmpty(loginId)) {
throw new SaSsoException("无效ticket" + ticket).setCode(SaSsoExceptionCode.CODE_20004);
} else {
// 3、如果 loginId 有值,说明 ticket 有效此时进行登录并重定向至back地址
stpLogic.login(loginId);
return res.redirect(back);
} else {
// 如果ticket无效:
throw new SaSsoException("无效ticket" + ticket).setCode(SaSsoExceptionCode.CODE_20004);
}
}
}
@@ -279,7 +295,6 @@ public class SaSsoHandle {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaSsoConfig cfg = SaSsoManager.getConfig();
StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;
// 如果未登录,则无需注销
@@ -289,17 +304,19 @@ public class SaSsoHandle {
// 调用SSO-Server认证中心API进行注销
String url = SaSsoUtil.buildSloUrl(stpLogic.getLoginId());
String body = String.valueOf(cfg.getSendHttp().apply(url));
if(SaSsoConsts.OK.equals(body) == false) {
return SaResult.error("单点注销失败");
}
SaResult result = request(url);
// 返回
return ssoLogoutBack(req, res);
// 校验
if(result.getCode() == SaResult.CODE_SUCCESS) {
return ssoLogoutBack(req, res);
} else {
// 将 sso-server 回应的消息作为异常抛出
throw new SaSsoException(result.getMsg()).setCode(SaSsoExceptionCode.CODE_20006);
}
}
/**
* SSO-Client端单点注销的回调 [模式三]
* SSO-Client端单点注销的回调 [模式三]
* @return 处理结果
*/
public static Object ssoLogoutCall() {
@@ -311,11 +328,17 @@ public class SaSsoHandle {
String loginId = req.getParam(ParamName.loginId);
String secretkey = req.getParam(ParamName.secretkey);
// 注销当前应用端会话
SaSsoUtil.checkSecretkey(secretkey);
stpLogic.logout(loginId);
return SaSsoConsts.OK;
// 响应
return SaResult.ok("单点注销回调成功");
}
// ----------- 工具方法
/**
* 封装:单点注销成功后返回结果
* @param req SaRequest对象
@@ -348,20 +371,41 @@ public class SaSsoHandle {
*/
public static Object checkTicket(String ticket, String currUri) {
SaSsoConfig cfg = SaSsoManager.getConfig();
// --------- 两种模式
if(cfg.getIsHttp()) {
// 模式三使用http请求校验ticket
// 模式三:使用 http 请求从认证中心校验ticket
String ssoLogoutCall = null;
if(cfg.getIsSlo()) {
ssoLogoutCall = SaHolder.getRequest().getUrl().replace(currUri, Api.ssoLogoutCall);
}
// 发起请求
String checkUrl = SaSsoUtil.buildCheckTicketUrl(ticket, ssoLogoutCall);
Object body = cfg.getSendHttp().apply(checkUrl);
return (SaFoxUtil.isEmpty(body) ? null : body);
SaResult result = request(checkUrl);
// 校验
if(result.getCode() == SaResult.CODE_SUCCESS) {
return result.getData();
} else {
// 将 sso-server 回应的消息作为异常抛出
throw new SaSsoException(result.getMsg()).setCode(SaSsoExceptionCode.CODE_20005);
}
} else {
// 模式二直连Redis校验ticket
return SaSsoUtil.checkTicket(ticket);
}
}
/**
* 发出请求,并返回 SaResult 结果
* @param url 请求地址
* @return 返回的结果
*/
public static SaResult request(String url) {
String body = SaSsoManager.getConfig().getSendHttp().apply(url);
Map<String, Object> map = SaManager.getSaJsonTemplate().parseJsonToMap(body);
return new SaResult(map);
}
}

View File

@@ -19,7 +19,11 @@ public class SaSsoExceptionCode {
/** 提供的 ticket 是无效的 */
public static final int CODE_20004 = 20004;
/** 在模式三下sso-client 调用 sso-server 端 校验ticket接口 时,得到的响应是校验失败 */
public static final int CODE_20005 = 20005;
/** 在模式三下sso-client 调用 sso-server 端 单点注销接口 时,得到的响应是注销失败 */
public static final int CODE_20006 = 20006;
}