diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/java/com/pj/SaSso2ClientApplication.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/java/com/pj/SaSso2ClientApplication.java index d19c7528..2ab50f98 100644 --- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/java/com/pj/SaSso2ClientApplication.java +++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/java/com/pj/SaSso2ClientApplication.java @@ -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(); } diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/resources/application.yml index bf59d24b..f971cae7 100644 --- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/resources/application.yml @@ -1,9 +1,11 @@ # 端口 server: - port: 9001 + port: 9002 # sa-token配置 -sa-token: +sa-token: + # 每次登录时,产生不同的token + is-share: false # SSO-相关配置 sso-client: # SSO-Server端 统一认证地址 diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/java/com/pj/SaSso3ClientApplication.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/java/com/pj/SaSso3ClientApplication.java index cdcd78ce..ff233b83 100644 --- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/java/com/pj/SaSso3ClientApplication.java +++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/java/com/pj/SaSso3ClientApplication.java @@ -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(); } diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml index 4d669453..f1bce7e4 100644 --- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml @@ -1,6 +1,6 @@ # 端口 server: - port: 9001 + port: 9003 # sa-token配置 sa-token: diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/model/SaSsoClientModel.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/model/SaSsoClientModel.java index db3ed6a4..81e51ca3 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/model/SaSsoClientModel.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/model/SaSsoClientModel.java @@ -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 + '}'; diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoClientProcessor.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoClientProcessor.java index eb04a659..d5b65596 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoClientProcessor.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoClientProcessor.java @@ -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()); } } diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoClientTemplate.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoClientTemplate.java index 7a2034e5..80b4d603 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoClientTemplate.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoClientTemplate.java @@ -42,6 +42,8 @@ public class SaSsoClientTemplate extends SaSsoTemplate { return SaSsoManager.getClientConfig(); } + + // ------------------- SSO 模式三相关 ------------------- /** diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoServerTemplate.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoServerTemplate.java index d9d922fc..1c60027b 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoServerTemplate.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoServerTemplate.java @@ -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 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 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 scmList) { + public int calcNextIndex(List 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 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 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 ---------------------- diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoTemplate.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoTemplate.java index 8a525e8d..39465185 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoTemplate.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoTemplate.java @@ -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(); } - } diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoUtil.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoUtil.java index 4ff93fc4..5b63e8af 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoUtil.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoUtil.java @@ -144,7 +144,7 @@ public class SaSsoUtil { } /** - * 指定账号单点注销 + * 指定账号单点注销 (以Server方发起) * @param loginId 指定账号 */ public static void ssoLogout(Object loginId) {