sso 模块新增 maxRegClient 属性,用于控制模式三下 client 注册数量

This commit is contained in:
click33
2024-05-01 05:53:18 +08:00
parent 7652a51592
commit 14a97a1fcb
10 changed files with 144 additions and 138 deletions

View File

@@ -13,9 +13,9 @@ public class SaSso2ClientApplication {
System.out.println();
System.out.println("---------------------- Sa-Token SSO 模式二 Client 端启动成功 ----------------------");
System.out.println("配置信息:" + SaSsoManager.getClientConfig());
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9001");
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9001");
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9001");
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9002");
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9002");
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9002");
System.out.println("测试前需要根据官网文档修改hosts文件测试账号密码sa / 123456");
System.out.println();
}

View File

@@ -1,9 +1,11 @@
# 端口
server:
port: 9001
port: 9002
# sa-token配置
sa-token:
sa-token:
# 每次登录时产生不同的token
is-share: false
# SSO-相关配置
sso-client:
# SSO-Server端 统一认证地址

View File

@@ -13,9 +13,9 @@ public class SaSso3ClientApplication {
System.out.println();
System.out.println("---------------------- Sa-Token SSO 模式三 Client 端启动成功 ----------------------");
System.out.println("配置信息:" + SaSsoManager.getClientConfig());
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9001");
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9001");
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9001");
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9003");
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9003");
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9003");
System.out.println("测试前需要根据官网文档修改hosts文件测试账号密码sa / 123456");
System.out.println();
}

View File

@@ -1,6 +1,6 @@
# 端口
server:
port: 9001
port: 9003
# sa-token配置
sa-token:

View File

@@ -16,6 +16,8 @@
package cn.dev33.satoken.sso.model;
import cn.dev33.satoken.sso.util.SaSsoConsts;
/**
* Sa-Token SSO Model
*
@@ -24,6 +26,11 @@ package cn.dev33.satoken.sso.model;
*/
public class SaSsoClientModel {
/*
* 只能记录模式三登录的 client 信息,模式一和模式二的信息即使记录上,也无法完成单点注销操作,遂不记录
* 所以mode、tokenValue 字段,仅留作扩展,暂时无用
*/
/**
* 此 client 登录模式1=模式一2=模式二3=模式三)
*/
@@ -34,15 +41,15 @@ public class SaSsoClientModel {
*/
public String client;
/**
* 此次登录 token 值
*/
public String tokenValue;
// /**
// * 此次登录 token 值
// */
// public String tokenValue;
/**
* 单点注销回调url
*/
public String ssoLogoutCall;
public String sloCallbackUrl;
/**
* 此 client 注册信息的时间13位时间戳
@@ -57,10 +64,15 @@ public class SaSsoClientModel {
public SaSsoClientModel() {
}
public SaSsoClientModel(String client, String ssoLogoutCall) {
/**
* 模式三构建
*/
public SaSsoClientModel(String client, String sloCallbackUrl, int index) {
this.mode = SaSsoConsts.SSO_MODE_3;
this.client = client;
this.ssoLogoutCall = ssoLogoutCall;
this.sloCallbackUrl = sloCallbackUrl;
this.regTime = System.currentTimeMillis();
this.index = index;
}
@@ -104,43 +116,43 @@ public class SaSsoClientModel {
return this;
}
/**
* 获取 此次登录 token 值
*
* @return tokenValue 此次登录 token 值
*/
public String getTokenValue() {
return this.tokenValue;
}
/**
* 设置 此次登录 token 值
*
* @param tokenValue 此次登录 token 值
* @return /
*/
public SaSsoClientModel setTokenValue(String tokenValue) {
this.tokenValue = tokenValue;
return this;
}
// /**
// * 获取 此次登录 token 值
// *
// * @return tokenValue 此次登录 token 值
// */
// public String getTokenValue() {
// return this.tokenValue;
// }
//
// /**
// * 设置 此次登录 token 值
// *
// * @param tokenValue 此次登录 token 值
// * @return /
// */
// public SaSsoClientModel setTokenValue(String tokenValue) {
// this.tokenValue = tokenValue;
// return this;
// }
/**
* 获取 单点注销回调url
*
* @return ssoLogoutCall 单点注销回调url
*/
public String getSsoLogoutCall() {
return this.ssoLogoutCall;
public String getSloCallbackUrl() {
return this.sloCallbackUrl;
}
/**
* 设置 单点注销回调url
*
* @param ssoLogoutCall 单点注销回调url
* @param sloCallbackUrl 单点注销回调url
* @return /
*/
public SaSsoClientModel setSsoLogoutCall(String ssoLogoutCall) {
this.ssoLogoutCall = ssoLogoutCall;
public SaSsoClientModel setSloCallbackUrl(String sloCallbackUrl) {
this.sloCallbackUrl = sloCallbackUrl;
return this;
}
@@ -189,8 +201,8 @@ public class SaSsoClientModel {
return "SaSsoClientModel{" +
"mode=" + mode +
", client='" + client + '\'' +
", tokenValue='" + tokenValue + '\'' +
", ssoLogoutCall='" + ssoLogoutCall + '\'' +
// ", tokenValue='" + tokenValue + '\'' +
", sloCallbackUrl='" + sloCallbackUrl + '\'' +
", regTime=" + regTime +
", index=" + index +
'}';

View File

@@ -227,10 +227,13 @@ public class SaSsoClientProcessor {
// 获取参数
String loginId = req.getParamNotNull(paramName.loginId);
// String client = req.getParam(paramName.client);
// String autoLogout = req.getParam(paramName.autoLogout);
// 校验参数签名
if(ssoConfig.getIsCheckSign()) {
ssoClientTemplate.getSignTemplate(ssoConfig.getClient()).checkRequest(req, paramName.loginId);
ssoClientTemplate.getSignTemplate(ssoConfig.getClient()).
checkRequest(req, paramName.loginId, paramName.client, paramName.autoLogout);
} else {
SaSsoManager.printNoCheckSignWarningByRuntime();
}
@@ -289,7 +292,11 @@ public class SaSsoClientProcessor {
}
} else {
// q2、使用模式二直连Redis校验ticket
// return ssoClientTemplate.checkTicket(ticket);
// 注意此处调用了 SaSsoServerProcessor 处理器里的方法,
// 这意味着如果你的 sso-server 端重写了 SaSsoServerProcessor 里的部分方法,
// 而在当前 sso-client 没有按照相应格式重写 SaSsoClientProcessor 里的方法,
// 可能会导致调用失败(注意是可能,而非一定),
// 解决方案为:在当前 sso-client 端也按照 sso-server 端的格式重写 SaSsoClientProcessor 里的方法
return SaSsoServerProcessor.instance.ssoServerTemplate.checkTicket(ticket, cfg.getClient());
}
}

View File

@@ -42,6 +42,8 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
return SaSsoManager.getClientConfig();
}
// ------------------- SSO 模式三相关 -------------------
/**

View File

@@ -17,12 +17,12 @@ package cn.dev33.satoken.sso.template;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.sso.util.SaSsoConsts;
import cn.dev33.satoken.sso.SaSsoManager;
import cn.dev33.satoken.sso.config.SaSsoServerConfig;
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
import cn.dev33.satoken.sso.exception.SaSsoException;
import cn.dev33.satoken.sso.model.SaSsoClientModel;
import cn.dev33.satoken.sso.util.SaSsoConsts;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaFoxUtil;
@@ -266,44 +266,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
}
// ------------------- SSO 模式三相关 -------------------
/**
* 为指定账号id注册单点注销回调URL
* @param loginId 账号id
* @param client 指定客户端标识可为null
* @param sloCallbackUrl 单点注销时的回调URL
*/
public void registerSloCallbackUrl(Object loginId, String client, String sloCallbackUrl) {
// 如果提供的参数是空值,则直接返回,不进行任何操作
if(SaFoxUtil.isEmpty(loginId) || SaFoxUtil.isEmpty(sloCallbackUrl)) {
return;
}
SaSession session = getStpLogic().getSessionByLoginId(loginId);
// 取出原来的
List<SaSsoClientModel> scmList = session.get(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, ArrayList::new);
// 将 新登录client 加入到集合中
SaSsoClientModel scm = new SaSsoClientModel();
scm.mode = 3;
scm.client = client;
scm.ssoLogoutCall = sloCallbackUrl;
scm.regTime = System.currentTimeMillis();
scm.index = calcNextIndex(scmList);
scmList.add(scm);
// 如果登录的client数量超过了限制则将最早的一个登录进行清退
if(scmList.size() > getServerConfig().getMaxRegClient()) {
SaSsoClientModel removeScm = scmList.remove(0);
notifyClientLogout(loginId, removeScm, true);
}
// 存入持久库
session.set(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, scmList);
}
// ------------------- SSO -------------------
/**
* 指定账号单点注销
@@ -327,60 +290,12 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
getStpLogic().logout(loginId);
}
/**
* 通知指定账号的指定客户端注销
* @param loginId 指定账号
* @param scm 客户端信息对象
* @param autoLogout 是否为超过 maxRegClient 的自动注销
*/
public void notifyClientLogout(Object loginId, SaSsoClientModel scm, boolean autoLogout) {
// 如果给个null值不进行任何操作
if(scm == null) {
return;
}
// 如果是模式二登录的
if(scm.mode == SaSsoConsts.SSO_MODE_2) {
// 获取登录 token
String tokenValue = scm.tokenValue;
if(SaFoxUtil.isEmpty(tokenValue)) {
return;
}
// 注销此 token
getStpLogic().logoutByTokenValue(scm.tokenValue);
}
// 如果是模式三登录的
else if(scm.mode != SaSsoConsts.SSO_MODE_3) {
// url
String sloCallUrl = scm.getSsoLogoutCall();
if(SaFoxUtil.isEmpty(sloCallUrl)) {
return;
}
// 参数
Map<String, Object> paramsMap = new TreeMap<>();
paramsMap.put(paramName.client, scm.getClient());
paramsMap.put(paramName.loginId, loginId);
paramsMap.put(paramName.autoLogout, autoLogout);
String signParamsStr = getSignTemplate(scm.getClient()).addSignParamsAndJoin(paramsMap);
// 拼接
String finalUrl = SaFoxUtil.joinParam(sloCallUrl, signParamsStr);
// 发起请求
getServerConfig().sendHttp.apply(finalUrl);
}
}
/**
* 计算下一个 index 值
* @param scmList /
* @return /
*/
private int calcNextIndex(List<SaSsoClientModel> scmList) {
public int calcNextIndex(List<SaSsoClientModel> scmList) {
// 如果目前还没有任何登录记录则直接返回0
if(scmList == null || scmList.isEmpty()) {
return 0;
@@ -394,7 +309,79 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
}
// 否则返回最大值+1
return maxIndex++;
maxIndex++;
return maxIndex;
}
/**
* 为指定账号id注册单点注销回调信息模式三
* @param loginId 账号id
* @param client 指定客户端标识可为null
* @param sloCallbackUrl 单点注销时的回调URL
*/
public void registerSloCallbackUrl(Object loginId, String client, String sloCallbackUrl) {
// 如果提供的参数是空值,则直接返回,不进行任何操作
if(SaFoxUtil.isEmpty(loginId)) {
return;
}
SaSession session = getStpLogic().getSessionByLoginId(loginId);
// 取出原来的
List<SaSsoClientModel> scmList = session.get(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, ArrayList::new);
// 将 新登录client 加入到集合中
SaSsoClientModel scm = new SaSsoClientModel(client, sloCallbackUrl, calcNextIndex(scmList));
scmList.add(scm);
// 如果登录的client数量超过了限制则从最早的一个登录开始清退
int maxRegClient = getServerConfig().maxRegClient;
if(maxRegClient != -1) {
for (;;) {
if(scmList.size() > maxRegClient) {
SaSsoClientModel removeScm = scmList.remove(0);
notifyClientLogout(loginId, removeScm, true);
} else {
break;
}
}
}
// 存入持久库
session.set(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, scmList);
}
/**
* 通知指定账号的指定客户端注销
* @param loginId 指定账号
* @param scm 客户端信息对象
* @param autoLogout 是否为超过 maxRegClient 的自动注销
*/
public void notifyClientLogout(Object loginId, SaSsoClientModel scm, boolean autoLogout) {
// 如果给个null值不进行任何操作
if(scm == null || scm.mode != SaSsoConsts.SSO_MODE_3) {
return;
}
// url
String sloCallUrl = scm.getSloCallbackUrl();
if(SaFoxUtil.isEmpty(sloCallUrl)) {
return;
}
// 参数
Map<String, Object> paramsMap = new TreeMap<>();
paramsMap.put(paramName.client, scm.getClient());
paramsMap.put(paramName.loginId, loginId);
paramsMap.put(paramName.autoLogout, autoLogout);
String signParamsStr = getSignTemplate(scm.getClient()).addSignParamsAndJoin(paramsMap);
// 拼接
String finalUrl = SaFoxUtil.joinParam(sloCallUrl, signParamsStr);
// 发起请求
getServerConfig().sendHttp.apply(finalUrl);
}
// ---------------------- 构建URL ----------------------

View File

@@ -21,9 +21,6 @@ import cn.dev33.satoken.sso.name.ApiName;
import cn.dev33.satoken.sso.name.ParamName;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import java.util.Map;
/**
* Sa-Token SSO 模板方法类 (公共端)
@@ -81,5 +78,4 @@ public class SaSsoTemplate {
return SaManager.getSaSignTemplate();
}
}

View File

@@ -144,7 +144,7 @@ public class SaSsoUtil {
}
/**
* 指定账号单点注销
* 指定账号单点注销 (以Server方发起)
* @param loginId 指定账号
*/
public static void ssoLogout(Object loginId) {