优化登录有效期策略,SSO Client 端登录时将延续 SSO Server 端的会话剩余有效期

This commit is contained in:
click33 2024-05-03 14:22:27 +08:00
parent cf1f255a4a
commit 5a7463dc91
5 changed files with 88 additions and 21 deletions

View File

@ -16,6 +16,7 @@
package cn.dev33.satoken.sso.exception;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.util.SaFoxUtil;
/**
@ -57,12 +58,38 @@ public class SaSsoException extends SaTokenException {
super.setCode(code);
return this;
}
/**
* 如果flag==true则抛出message异常
* 断言 flag 不为 true否则抛出 message 异常
* @param flag 标记
* @param message 异常信息
* @param message 异常信息
* @param code 异常细分状态码
*/
public static void notTrue(boolean flag, String message, int code) {
if(flag) {
throw new SaSsoException(message).setCode(code);
}
}
/**
* 断言 value 不为空否则抛出 message 异常
* @param value
* @param message 异常信息
* @param code 异常细分状态码
*/
public static void notEmpty(Object value, String message, int code) {
if(SaFoxUtil.isEmpty(value)) {
throw new SaSsoException(message).setCode(code);
}
}
/**
* 如果flag==true则抛出message异常
* @param flag 标记
* @param message 异常信息
*/
@Deprecated
public static void throwBy(boolean flag, String message) {
if(flag) {
throw new SaSsoException(message);

View File

@ -15,6 +15,8 @@
*/
package cn.dev33.satoken.sso.function;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
import java.util.function.BiFunction;
/**
@ -27,6 +29,6 @@ import java.util.function.BiFunction;
* @since 1.38.0
*/
@FunctionalInterface
public interface TicketResultHandleFunction extends BiFunction<Object, String, Object> {
public interface TicketResultHandleFunction extends BiFunction<SaSsoClientProcessor.CheckTicketResult, String, Object> {
}

View File

@ -57,4 +57,7 @@ public class ParamName {
public String nonce = "nonce";
public String sign = "sign";
/** Session 剩余有效期 参数名称 */
public String remainSessionTimeout = "remainSessionTimeout";
}

View File

@ -121,22 +121,17 @@ public class SaSsoClientProcessor {
String serverAuthUrl = ssoClientTemplate.buildServerAuthUrl(currSsoLoginUrl, back);
return res.redirect(serverAuthUrl);
} else {
// ------- 1校验ticket获取 loginId
Object loginId = checkTicketByMode2Or3(ticket, apiName.ssoLogin);
// 1校验ticket获取 loginId
CheckTicketResult ctr = checkTicketByMode2Or3(ticket, apiName.ssoLogin);
// Be: 如果开发者自定义了处理逻辑
// 2如果开发者自定义了ticket结果值处理函数则使用自定义的函数
if(cfg.ticketResultHandle != null) {
return cfg.ticketResultHandle.apply(loginId, back);
return cfg.ticketResultHandle.apply(ctr, back);
}
// ------- 2如果 loginId 无值说明 ticket 无效
if(SaFoxUtil.isEmpty(loginId)) {
throw new SaSsoException("无效ticket" + ticket).setCode(SaSsoErrorCode.CODE_30004);
} else {
// 3如果 loginId 有值说明 ticket 有效此时进行登录并重定向至back地址
stpLogic.login(loginId);
return res.redirect(back);
}
// 3登录并重定向至back地址
stpLogic.login(ctr.loginId, ctr.remainSessionTimeout);
return res.redirect(back);
}
}
@ -244,14 +239,15 @@ public class SaSsoClientProcessor {
// 工具方法
/**
* 封装校验ticket取出loginId
* 封装校验ticket取出loginId如果 ticket 无效则抛出异常
* @param ticket ticket码
* @param currUri 当前路由的uri用于计算单点注销回调地址
* @return loginId
*/
public Object checkTicketByMode2Or3(String ticket, String currUri) {
public CheckTicketResult checkTicketByMode2Or3(String ticket, String currUri) {
SaSsoClientConfig cfg = ssoClientTemplate.getClientConfig();
ApiName apiName = ssoClientTemplate.apiName;
ParamName paramName = ssoClientTemplate.paramName;
// --------- 两种模式
if(cfg.getIsHttp()) {
@ -281,7 +277,18 @@ public class SaSsoClientProcessor {
// 校验
if(result.getCode() != null && result.getCode() == SaResult.CODE_SUCCESS) {
return result.getData();
// 取出 loginId
Object loginId = result.getData();
if(SaFoxUtil.isEmpty(loginId)) {
throw new SaSsoException("无效ticket" + ticket).setCode(SaSsoErrorCode.CODE_30004);
}
// 取出 Session 剩余有效期
Long remainSessionTimeout = result.get(paramName.remainSessionTimeout, Long.class);
if(remainSessionTimeout == null) {
remainSessionTimeout = ssoClientTemplate.getStpLogic().getConfig().getTimeout();
}
// 构建返回
return new CheckTicketResult(loginId, remainSessionTimeout);
} else {
// sso-server 回应的消息作为异常抛出
throw new SaSsoException(result.getMsg()).setCode(SaSsoErrorCode.CODE_30005);
@ -293,7 +300,16 @@ public class SaSsoClientProcessor {
// 而在当前 sso-client 没有按照相应格式重写 SaSsoClientProcessor 里的方法
// 可能会导致调用失败注意是可能而非一定
// 解决方案为在当前 sso-client 端也按照 sso-server 端的格式重写 SaSsoClientProcessor 里的方法
return SaSsoServerProcessor.instance.ssoServerTemplate.checkTicket(ticket, cfg.getClient());
// 取出 loginId
Object loginId = SaSsoServerProcessor.instance.ssoServerTemplate.checkTicket(ticket, cfg.getClient());
if(SaFoxUtil.isEmpty(loginId)) {
throw new SaSsoException("无效ticket" + ticket).setCode(SaSsoErrorCode.CODE_30004);
}
// 取出 Session 剩余有效期
long remainSessionTimeout = ssoClientTemplate.getStpLogic().getSessionTimeoutByLoginId(loginId);
// 构建返回
return new CheckTicketResult(loginId, remainSessionTimeout);
}
}
@ -307,4 +323,21 @@ public class SaSsoClientProcessor {
return SaSsoProcessorHelper.ssoLogoutBack(req, res, ssoClientTemplate.paramName);
}
public static class CheckTicketResult {
public Object loginId;
public long remainSessionTimeout;
public CheckTicketResult(Object loginId, long remainSessionTimeout) {
this.loginId = loginId;
this.remainSessionTimeout = remainSessionTimeout;
}
@Override
public String toString() {
return "CheckTicketResult{" +
"loginId=" + loginId +
", remainSessionTimeout=" + remainSessionTimeout +
'}';
}
}
}

View File

@ -193,7 +193,9 @@ public class SaSsoServerProcessor {
ssoServerTemplate.registerSloCallbackUrl(loginId, client, sloCallback);
// 6 client 端响应结果
return SaResult.data(loginId);
long remainSessionTimeout = ssoServerTemplate.getStpLogic().getSessionTimeoutByLoginId(loginId);
return SaResult.data(loginId)
.set(paramName.remainSessionTimeout, remainSessionTimeout);
}
/**