refactor: 重构 sa-token-sso 模块代码及注释,提高代码可读性

This commit is contained in:
click33 2025-05-05 12:55:52 +08:00
parent b59fa26edf
commit 213d98d848
36 changed files with 1075 additions and 649 deletions

View File

@ -22,7 +22,7 @@ public class SsoClientController implements Render {
@Mapping("/")
public String index() {
String authUrl = SaSsoManager.getClientConfig().splicingAuthUrl();
String solUrl = SaSsoManager.getClientConfig().splicingSloUrl();
String solUrl = SaSsoManager.getClientConfig().splicingSignoutUrl();
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
"<p>当前会话是否登录:" + StpUtil.isLogin() + "</p>" +
"<p><a href=\"javascript:location.href='" + authUrl + "?mode=simple&redirect=' + encodeURIComponent(location.href);\">登录</a> " +

View File

@ -18,7 +18,7 @@ public class SsoClientController {
@RequestMapping("/")
public String index() {
String authUrl = SaSsoManager.getClientConfig().splicingAuthUrl();
String solUrl = SaSsoManager.getClientConfig().splicingSloUrl();
String solUrl = SaSsoManager.getClientConfig().splicingSignoutUrl();
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
"<p>当前会话是否登录:" + StpUtil.isLogin() + "</p>" +
"<p><a href=\"javascript:location.href='" + authUrl + "?mode=simple&redirect=' + encodeURIComponent(location.href);\">登录</a> " +

View File

@ -20,7 +20,7 @@ public class SsoClientController {
// 首页
@RequestMapping("/")
public String index() {
String solUrl = SaSsoManager.getClientConfig().splicingSloUrl();
String solUrl = SaSsoManager.getClientConfig().splicingSignoutUrl();
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
"<p>当前会话是否登录:" + StpUtil.isLogin() + "</p>" +
"<p><a href=\"javascript:location.href='/sso/login?back=' + encodeURIComponent(location.href);\">登录</a> " +

View File

@ -70,18 +70,18 @@ public class SaSsoManager {
}
}
// 在启动时检测到 sa-token.sso.is-check-sign=false 输出警告信息
// 在启动时检测到 sa-token.sso-[server/client].is-check-sign=false 输出警告信息
public static void printNoCheckSignWarningByStartup() {
System.err.println("-----------------------------------------------------------------------------");
System.err.println("警告信息:");
System.err.println("当前配置项 sa-token.sso.is-check-sign=false 代表跳过 SSO 参数签名校验");
System.err.println("当前配置项 sa-token.sso-[server/client].is-check-sign=false 代表跳过 SSO 参数签名校验");
System.err.println("此模式仅为方便本地调试使用,生产环境下请务必配置为 true 配置项默认为true");
System.err.println("-----------------------------------------------------------------------------");
}
// 在运行时检测到 sa-token.sso.is-check-sign=false 输出警告信息
// 在运行时检测到 sa-token.sso-[server/client].is-check-sign=false 输出警告信息
public static void printNoCheckSignWarningByRuntime() {
System.err.println("警告信息:当前配置项 sa-token.sso.is-check-sign=false 已跳过参数签名校验," +
System.err.println("警告信息:当前配置项 sa-token.sso-[server/client].is-check-sign=false 已跳过参数签名校验," +
"此模式仅为方便本地调试使用,生产环境下请务必配置为 true 配置项默认为true");
}

View File

@ -21,7 +21,7 @@ import cn.dev33.satoken.util.SaFoxUtil;
import java.io.Serializable;
/**
* Sa-Token SSO 单点登录模块 配置类 Client端
* Sa-Token SSO Client 配置类
*
* @author click33
* @since 1.30.0
@ -36,35 +36,35 @@ public class SaSsoClientConfig implements Serializable {
public String mode = "";
/**
* 当前 Client 标识
* 当前 Client 标识非必填不填时代表当前应用是一个匿名应用
*/
public String client;
/**
* 配置 Server 端主机总地址
* 配置 SSO Server 端主机总地址
*/
public String serverUrl;
/**
* 单独配置 Server 单点登录授权地址
* 单独配置 Server 单点登录授权地址
*/
public String authUrl = "/sso/auth";
/**
* 单独配置 Server 查询数据 getData 地址
* 单独配置 Server 单点注销地址
*/
public String getDataUrl = "/sso/getData";
public String signoutUrl = "/sso/signout";
/**
* 单独配置 Server 端单点注销地址
*/
public String sloUrl = "/sso/signout";
/**
* 单独配置 Server 端推送消息地址
* 单独配置 Server 推送消息地址
*/
public String pushUrl = "/sso/pushS";
/**
* 单独配置 Server 查询数据 getData 地址
*/
public String getDataUrl = "/sso/getData";
/**
* 配置当前 Client 端的登录地址为空时自动获取
*/
@ -75,6 +75,11 @@ public class SaSsoClientConfig implements Serializable {
*/
public String currSsoLogoutCall;
/**
* 是否打开模式三此值为 true 时将使用 http 请求校验 ticket
*/
public Boolean isHttp = false;
/**
* 是否打开单点注销功能 ( true 接收单点注销回调消息推送)
*/
@ -85,18 +90,13 @@ public class SaSsoClientConfig implements Serializable {
*/
public Boolean regLogoutCall = false;
/**
* 是否打开模式三此值为 true 时将使用 http 请求校验 ticket
*/
public Boolean isHttp = false;
/**
* API 调用签名秘钥
*/
public String secretKey;
/**
* 是否校验参数签名方便本地调试用的一个配置项生产环境请务必为true
* 是否校验参数签名 false 时暂时关闭参数签名校验此为方便本地调试用的一个配置项生产环境请务必为true
*/
public Boolean isCheckSign = true;
@ -104,28 +104,28 @@ public class SaSsoClientConfig implements Serializable {
// 额外添加的一些函数
/**
* @return 获取拼接urlServer 端单点登录授权地址
* @return 获取拼接 urlServer 端单点登录授权地址
*/
public String splicingAuthUrl() {
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getAuthUrl());
}
/**
* @return 获取拼接urlServer 端查询数据 getData 地址
* @return 获取拼接 urlServer 端查询数据 getData 地址
*/
public String splicingGetDataUrl() {
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getGetDataUrl());
}
/**
* @return 获取拼接urlServer 端单点注销地址
* @return 获取拼接 urlServer 端单点注销地址
*/
public String splicingSloUrl() {
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getSloUrl());
public String splicingSignoutUrl() {
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getSignoutUrl());
}
/**
* @return 获取拼接url单独配置 Server 端推送消息地址
* @return 获取拼接 url单独配置 Server 端推送消息地址
*/
public String splicingPushUrl() {
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getPushUrl());
@ -153,14 +153,14 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* @return 是否打开单点注销功能
* @return 是否打开单点注销功能 ( true 接收单点注销回调消息推送)
*/
public Boolean getIsSlo() {
return isSlo;
}
/**
* @param isSlo 是否打开单点注销功能
* @param isSlo 是否打开单点注销功能 ( true 接收单点注销回调消息推送)
* @return 对象自身
*/
public SaSsoClientConfig setIsSlo(Boolean isSlo) {
@ -169,14 +169,14 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* @return isHttp 是否打开模式三此值为 true 时将使用 http 请求校验ticket值单点注销拉取数据getData
* @return isHttp 是否打开模式三此值为 true 时将使用 http 请求校验 ticket
*/
public Boolean getIsHttp() {
return isHttp;
}
/**
* @param isHttp 是否打开模式三此值为 true 时将使用 http 请求校验ticket值单点注销拉取数据getData
* @param isHttp 是否打开模式三此值为 true 时将使用 http 请求校验 ticket
* @return 对象自身
*/
public SaSsoClientConfig setIsHttp(Boolean isHttp) {
@ -185,14 +185,18 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* @return 当前 Client 名称标识用于和 ticket 码的互相锁定
* 当前 Client 标识非必填不填时代表当前应用是一个匿名应用
*
* @return /
*/
public String getClient() {
return client;
}
/**
* @param client 当前 Client 名称标识用于和 ticket 码的互相锁定
* 当前 Client 标识非必填不填时代表当前应用是一个匿名应用
*
* @param client /
*/
public SaSsoClientConfig setClient(String client) {
this.client = client;
@ -200,14 +204,14 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* @return 配置 Server 单点登录授权地址
* @return 单独配置 Server 单点登录授权地址
*/
public String getAuthUrl() {
return authUrl;
}
/**
* @param authUrl 配置 Server 单点登录授权地址
* @param authUrl 单独配置 Server 单点登录授权地址
* @return 对象自身
*/
public SaSsoClientConfig setAuthUrl(String authUrl) {
@ -216,14 +220,14 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* @return Server 查询数据 getData 地址
* @return 单独配置 Server 查询数据 getData 地址
*/
public String getGetDataUrl() {
return getDataUrl;
}
/**
* @param getDataUrl 配置 Server 查询数据 getData 地址
* @param getDataUrl 单独配置 Server 查询数据 getData 地址
* @return 对象自身
*/
public SaSsoClientConfig setGetDataUrl(String getDataUrl) {
@ -232,23 +236,23 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* @return 配置 Server 单点注销地址
* @return 单独配置 Server 单点注销地址
*/
public String getSloUrl() {
return sloUrl;
public String getSignoutUrl() {
return signoutUrl;
}
/**
* @param sloUrl 配置 Server 单点注销地址
* @param signoutUrl 单独配置 Server 单点注销地址
* @return 对象自身
*/
public SaSsoClientConfig setSloUrl(String sloUrl) {
this.sloUrl = sloUrl;
public SaSsoClientConfig setSignoutUrl(String signoutUrl) {
this.signoutUrl = signoutUrl;
return this;
}
/**
* 获取 单独配置 Server 推送消息地址
* 获取 单独配置 Server 推送消息地址
*
* @return /
*/
@ -257,7 +261,7 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* 设置 单独配置 Server 推送消息地址
* 设置 单独配置 Server 推送消息地址
*
* @param pushUrl /
* @return 对象自身
@ -300,14 +304,18 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* @return 配置的 Server 端主机总地址拼接在 authUrlcheckTicketUrlgetDataUrlsloUrl 属性前面用以简化各种 url 配置
* 配置 SSO Server 端主机总地址
*
* @return /
*/
public String getServerUrl() {
return serverUrl;
}
/**
* @param serverUrl 配置 Server 端主机总地址拼接在 authUrlcheckTicketUrlgetDataUrlsloUrl 属性前面用以简化各种 url 配置
* 配置 SSO Server 端主机总地址
*
* @param serverUrl /
* @return 对象自身
*/
public SaSsoClientConfig setServerUrl(String serverUrl) {
@ -336,7 +344,7 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* 获取 是否校验参数签名方便本地调试用的一个配置项生产环境请务必为true
* 获取 是否校验参数签名 false 时暂时关闭参数签名校验此为方便本地调试用的一个配置项生产环境请务必为true
*
* @return isCheckSign 是否校验参数签名方便本地调试用的一个配置项生产环境请务必为true
*/
@ -345,7 +353,7 @@ public class SaSsoClientConfig implements Serializable {
}
/**
* 设置 是否校验参数签名方便本地调试用的一个配置项生产环境请务必为true
* 设置 是否校验参数签名 false 时暂时关闭参数签名校验此为方便本地调试用的一个配置项生产环境请务必为true
*
* @param isCheckSign 是否校验参数签名方便本地调试用的一个配置项生产环境请务必为true
*/
@ -381,8 +389,9 @@ public class SaSsoClientConfig implements Serializable {
+ ", client=" + client
+ ", serverUrl=" + serverUrl
+ ", authUrl=" + authUrl
+ ", signoutUrl=" + signoutUrl
+ ", pushUrl=" + pushUrl
+ ", getDataUrl=" + getDataUrl
+ ", sloUrl=" + sloUrl
+ ", currSsoLogin=" + currSsoLogin
+ ", currSsoLogoutCall=" + currSsoLogoutCall
+ ", isHttp=" + isHttp

View File

@ -16,6 +16,8 @@
package cn.dev33.satoken.sso.config;
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
import cn.dev33.satoken.sso.exception.SaSsoException;
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
import cn.dev33.satoken.util.SaFoxUtil;
@ -23,29 +25,29 @@ import java.io.Serializable;
import java.util.List;
/**
* Sa-Token SSO 客户端信息配置
* Sa-Token SSO 客户端信息配置 Server 端配置允许接入的 Client 信息
*
* @author click33
* @since 1.42.0
* @since 1.43.0
*/
public class SaSsoClientModel implements Serializable {
private static final long serialVersionUID = -6541180061782004705L;
/**
* 当前 Client 名称标识用于和 ticket 码的互相锁定
* Client 名称标识
*/
public String client;
/**
* 所有允许的授权回调地址多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
* 所有允许的授权回调地址多个用逗号隔开 (不在此列表中的 URL 将禁止下放 ticket )
*/
public String allowUrl = "*";
/**
* 是否打开模式三此值为 true 时使用 http 调用方式进行消息通知
* 是否接收推送消息
*/
public Boolean isHttp = false;
public Boolean isPush = false;
/**
* 是否打开单点注销功能
@ -63,7 +65,7 @@ public class SaSsoClientModel implements Serializable {
public String serverUrl;
/**
* Client 端推送消息的地址
* Client 端推送消息的地址 (如不配置默认根据 serverUrl + '/sso/pushC' 进行拼接)
*/
public String pushUrl = "/sso/pushC";
@ -85,8 +87,12 @@ public class SaSsoClientModel implements Serializable {
*
* @return /
*/
public String splicingNoticeUrl() {
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getPushUrl());
public String splicingPushUrl() {
String _pushUrl = SaFoxUtil.spliceTwoUrl(getServerUrl(), getPushUrl());
if ( ! SaFoxUtil.isUrl(_pushUrl)) {
throw new SaSsoException("应用 [" + getClient() + "] 推送地址无效:" + _pushUrl).setCode(SaSsoErrorCode.CODE_30023);
}
return _pushUrl;
}
/**
@ -94,22 +100,22 @@ public class SaSsoClientModel implements Serializable {
*
* @return /
*/
public boolean isValidNoticeUrl() {
return SaFoxUtil.isUrl(splicingNoticeUrl());
public boolean isValidPushUrl() {
return SaFoxUtil.isUrl(splicingPushUrl());
}
// get set
/**
* @return 当前 Client 名称标识
* @return Client 名称标识
*/
public String getClient() {
return client;
}
/**
* @param client 当前 Client 名称标识
* @param client Client 名称标识
*/
public SaSsoClientModel setClient(String client) {
this.client = client;
@ -117,14 +123,14 @@ public class SaSsoClientModel implements Serializable {
}
/**
* @return 所有允许的授权回调地址多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
* @return 所有允许的授权回调地址多个用逗号隔开 (不在此列表中的 URL 将禁止下放 ticket )
*/
public String getAllowUrl() {
return allowUrl;
}
/**
* @param allowUrl 所有允许的授权回调地址多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
* @param allowUrl 所有允许的授权回调地址多个用逗号隔开 (不在此列表中的 URL 将禁止下放 ticket )
* @return 对象自身
*/
public SaSsoClientModel setAllowUrl(String allowUrl) {
@ -140,16 +146,16 @@ public class SaSsoClientModel implements Serializable {
/**
* @return isHttp 是否打开模式三
*/
public Boolean getIsHttp() {
return isHttp;
public Boolean getIsPush() {
return isPush;
}
/**
* @param isHttp 是否打开模式三
* @param isPush 是否打开模式三
* @return 对象自身
*/
public SaSsoClientModel setIsHttp(Boolean isHttp) {
this.isHttp = isHttp;
public SaSsoClientModel setIsPush(Boolean isPush) {
this.isPush = isPush;
return this;
}
@ -210,16 +216,16 @@ public class SaSsoClientModel implements Serializable {
}
/**
* 获取 Client 端推送消息的地址
* 获取 Client 端推送消息的地址 (如不配置默认根据 serverUrl + '/sso/pushC' 进行拼接)
*
* @return noticeUrl Client 端推送消息的地址
* @return /
*/
public String getPushUrl() {
return this.pushUrl;
}
/**
* 设置 Client 端推送消息的地址
* 设置 Client 端推送消息的地址 (如不配置默认根据 serverUrl + '/sso/pushC' 进行拼接)
*
* @param pushUrl Client 端推送消息的地址
* @return 对象自身
@ -235,7 +241,7 @@ public class SaSsoClientModel implements Serializable {
+ "client=" + client
+ ", allowUrl=" + allowUrl
+ ", isSlo=" + isSlo
+ ", isHttp=" + isHttp
+ ", isPush=" + isPush
+ ", secretKey=" + secretKey
+ ", serverUrl=" + serverUrl
+ ", pushUrl=" + pushUrl

View File

@ -25,7 +25,7 @@ import java.util.List;
import java.util.Map;
/**
* Sa-Token SSO 单点登录模块 配置类 Server端
* Sa-Token SSO Server 配置类
*
* @author click33
* @since 1.38.0
@ -43,7 +43,7 @@ public class SaSsoServerConfig implements Serializable {
public String mode = "";
/**
* Ticket有效期 (单位: )
* ticket 有效期 (单位: )
*/
public long ticketTimeout = 60 * 5;
@ -53,7 +53,7 @@ public class SaSsoServerConfig implements Serializable {
public String homeRoute;
/**
* 是否打开单点注销功能
* 是否打开单点注销功能 ( true 时接收 client 端推送的单点注销消息)
*/
public Boolean isSlo = true;
@ -98,7 +98,7 @@ public class SaSsoServerConfig implements Serializable {
// 额外方法
/**
* 以数组形式写入允许的授权回调地址
* 以数组形式写入允许的授权回调地址 (不在此列表中的URL将禁止下放ticket) (匿名 client 使用)
* @param url 所有集合
* @return 对象自身
*/
@ -139,14 +139,14 @@ public class SaSsoServerConfig implements Serializable {
}
/**
* @return Ticket有效期 (单位: )
* @return ticket 有效期 (单位: )
*/
public long getTicketTimeout() {
return ticketTimeout;
}
/**
* @param ticketTimeout Ticket有效期 (单位: )
* @param ticketTimeout ticket 有效期 (单位: )
* @return 对象自身
*/
public SaSsoServerConfig setTicketTimeout(long ticketTimeout) {
@ -192,14 +192,14 @@ public class SaSsoServerConfig implements Serializable {
}
/**
* @return 是否打开单点注销功能
* @return 是否打开单点注销功能 ( true 时接收 client 端推送的单点注销消息)
*/
public Boolean getIsSlo() {
return isSlo;
}
/**
* @param isSlo 是否打开单点注销功能
* @param isSlo 是否打开单点注销功能 ( true 时接收 client 端推送的单点注销消息)
* @return 对象自身
*/
public SaSsoServerConfig setIsSlo(Boolean isSlo) {

View File

@ -77,4 +77,7 @@ public interface SaSsoErrorCode {
/** 无效的消息推送地址 */
int CODE_30023 = 30023;
/** SSO 消息里缺少指定的参数 */
int CODE_30024 = 30024;
}

View File

@ -20,7 +20,7 @@ import cn.dev33.satoken.util.SaResult;
import java.util.function.BiFunction;
/**
* 函数式接口SSO-Server在校验 ticket sso-client 端追加返回信息的函数
* 函数式接口sso-server 在校验 ticket sso-client 端追加返回信息的函数
*
* <p> 参数loginId, SaResult 响应参数对象 </p>
* <p> 返回SaResult 响应参数对象 </p>

View File

@ -18,7 +18,7 @@ package cn.dev33.satoken.sso.function;
import java.util.function.BiFunction;
/**
* 函数式接口SSO-Server登录处理函数
* 函数式接口sso-server 登录处理函数
*
* <p> 参数账号密码 </p>
* <p> 返回登录结果 </p>

View File

@ -18,7 +18,7 @@ package cn.dev33.satoken.sso.function;
import java.util.function.Supplier;
/**
* 函数式接口SSO-Server端未登录时返回的View
* 函数式接口sso-server 未登录时返回的 View
*
* <p> 参数 </p>
* <p> 返回未登录时的 View 视图 </p>

View File

@ -18,7 +18,7 @@ package cn.dev33.satoken.sso.function;
import java.util.function.Function;
/**
* 函数式接口发送Http请求的处理函数
* 函数式接口发送 Http 请求的处理函数
*
* <p> 参数要请求的url </p>
* <p> 返回请求结果 </p>

View File

@ -18,7 +18,7 @@ package cn.dev33.satoken.sso.function;
import cn.dev33.satoken.sso.model.SaCheckTicketResult;
/**
* 函数式接口SSO-Client自定义校验 ticket 返回值的处理逻辑 每次从认证中心获取校验 ticket 的结果后调用
* 函数式接口sso-client 自定义校验 ticket 返回值的处理逻辑 每次从认证中心获取校验 ticket 的结果后调用
*
* <p> 参数loginId, back </p>
* <p> 返回返回给前端的值 </p>

View File

@ -26,7 +26,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
/**
* Sa-Token SSO 消息 Model
* SSO 消息 Model
*
* @author click33
* @since 1.43.0
@ -108,4 +108,19 @@ public class SaSsoMessage extends LinkedHashMap<String, Object> implements SaSet
return this;
}
// -----------
/**
* 获取一个值 此值必须存在否则抛出异常
* @param key
* @return 参数值
*/
public Object getValueNotNull(String key) {
Object value = get(key);
if(SaFoxUtil.isEmpty(value)) {
throw new SaSsoException("缺少参数:" + key).setCode(SaSsoErrorCode.CODE_30024);
}
return value;
}
}

View File

@ -25,7 +25,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
/**
* Sa-Token SSO 消息处理器持有者
* SSO 消息处理器 - 持有器
*
* @author click33
* @since 1.43.0
@ -33,7 +33,7 @@ import java.util.Map;
public class SaSsoMessageHolder {
/**
* 所有消息处理器的集合
* 所有已注册的消息处理器
*/
public final Map<String, SaSsoMessageHandle> messageHandleMap = new LinkedHashMap<>();
@ -61,6 +61,7 @@ public class SaSsoMessageHolder {
* 添加指定类型的消息处理器
*
* @param handle /
* @return 对象自身
*/
public SaSsoMessageHolder addHandle(SaSsoMessageHandle handle) {
messageHandleMap.put(handle.getHandlerType(), handle);
@ -81,7 +82,7 @@ public class SaSsoMessageHolder {
*
* @param ssoTemplate /
* @param message /
* @return /
* @return 处理结果
*/
public Object handleMessage(SaSsoTemplate ssoTemplate, SaSsoMessage message) {
SaSsoMessageHandle handle = messageHandleMap.get(message.getType());

View File

@ -20,7 +20,7 @@ import cn.dev33.satoken.sso.message.SaSsoMessage;
import cn.dev33.satoken.sso.template.SaSsoTemplate;
/**
* Sa-Token SSO 消息 处理器
* SSO 消息处理器 - 父接口
*
* @author click33
* @since 1.43.0
@ -35,7 +35,7 @@ public interface SaSsoMessageHandle {
String getHandlerType();
/**
* 执行方法
* 具体要执行的处理方法
*
* @param ssoTemplate /
* @param message /

View File

@ -29,7 +29,7 @@ import cn.dev33.satoken.stp.parameter.SaLogoutParameter;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token SSO 消息 处理器 - sso-client 处理 单点注销回调 的请求
* SSO 消息处理器 - sso-client 处理 单点注销回调 的请求
*
* @author click33
* @since 1.43.0
@ -53,27 +53,28 @@ public class SaSsoMessageLogoutCallHandle implements SaSsoMessageHandle {
* @return /
*/
public Object handle(SaSsoTemplate ssoTemplate, SaSsoMessage message) {
// 1获取对象
SaSsoClientTemplate ssoClientTemplate = (SaSsoClientTemplate) ssoTemplate;
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
ParamName paramName = ssoClientTemplate.paramName;
// 2判断当前应用是否开启单点注销功能
if( ! ssoClientTemplate.getClientConfig().getIsSlo()) {
return SaResult.error("当前 sso-client 端未开启单点注销功能");
}
// 获取对象
SaRequest req = SaHolder.getRequest();
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
ParamName paramName = ssoClientTemplate.paramName;
// 获取参数
Object loginId = req.getParamNotNull(paramName.loginId);
// 3获取参数
Object loginId = message.getValueNotNull(paramName.loginId);
loginId = ssoClientTemplate.strategy.convertCenterIdToLoginId.run(loginId);
String deviceId = message.getString(paramName.deviceId);
// 注销当前应用端会话
// 4注销当前应用端会话
stpLogic.logout(loginId, new SaLogoutParameter()
.setDeviceId(deviceId)
);
// 响应
// 5响应
return SaResult.ok("单点注销回调成功");
}

View File

@ -16,9 +16,6 @@
package cn.dev33.satoken.sso.message.handle.server;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.sso.config.SaSsoServerConfig;
import cn.dev33.satoken.sso.message.SaSsoMessage;
import cn.dev33.satoken.sso.message.handle.SaSsoMessageHandle;
import cn.dev33.satoken.sso.model.TicketModel;
@ -30,7 +27,7 @@ import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token SSO 消息 处理器 - sso-server 处理校验 ticket 的请求
* SSO 消息处理器 - sso-server 处理校验 ticket 的请求
*
* @author click33
* @since 1.43.0
@ -54,38 +51,23 @@ public class SaSsoMessageCheckTicketHandle implements SaSsoMessageHandle {
* @return /
*/
public Object handle(SaSsoTemplate ssoTemplate, SaSsoMessage message) {
// 1获取对象
SaSsoServerTemplate ssoServerTemplate = (SaSsoServerTemplate) ssoTemplate;
ParamName paramName = ssoServerTemplate.paramName;
// 1获取参数
SaRequest req = SaHolder.getRequest();
SaSsoServerConfig ssoServerConfig = ssoServerTemplate.getServerConfig();
StpLogic stpLogic = ssoServerTemplate.getStpLogic();
String client = req.getParam(paramName.client);
String ticket = req.getParamNotNull(paramName.ticket);
String sloCallback = req.getParam(paramName.ssoLogoutCall);
String client = message.getString(paramName.client);
String ticket = message.getValueNotNull(paramName.ticket).toString();
String sloCallback = message.getString(paramName.ssoLogoutCall);
// 2校验提供的client是否为非法字符
if(SaSsoConsts.CLIENT_WILDCARD.equals(client)) {
return SaResult.error("无效 client 标识:" + client);
}
// 3校验签名
// if(ssoServerConfig.getIsCheckSign()) {
// ssoServerTemplate.getSignTemplate(client).checkRequest(req, paramName.client, paramName.ticket, paramName.ssoLogoutCall);
// } else {
// SaSsoManager.printNoCheckSignWarningByRuntime();
// }
// 4校验ticket获取 loginId
// 2校验ticket获取 loginId
TicketModel ticketModel = ssoServerTemplate.checkTicketParamAndDelete(ticket, client);
Object loginId = ticketModel.getLoginId();
// 5注册此客户端的单点注销回调URL
// 3注册此客户端的登录信息
ssoServerTemplate.registerSloCallbackUrl(loginId, client, sloCallback);
// 6 client 端响应结果
// 4 client 端响应结果
SaResult result = SaResult.ok();
result.setData(loginId); // 兼容历史版本
result.set(paramName.loginId, loginId);
@ -93,7 +75,6 @@ public class SaSsoMessageCheckTicketHandle implements SaSsoMessageHandle {
result.set(paramName.deviceId, stpLogic.getLoginDeviceIdByToken(ticketModel.getTokenValue()));
result.set(paramName.remainTokenTimeout, stpLogic.getTokenTimeout(ticketModel.getTokenValue()));
result.set(paramName.remainSessionTimeout, stpLogic.getSessionTimeoutByLoginId(loginId));
result = ssoServerTemplate.strategy.checkTicketAppendData.apply(loginId, result);
return result;
}

View File

@ -16,8 +16,6 @@
package cn.dev33.satoken.sso.message.handle.server;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.sso.message.SaSsoMessage;
import cn.dev33.satoken.sso.message.handle.SaSsoMessageHandle;
import cn.dev33.satoken.sso.name.ParamName;
@ -28,7 +26,7 @@ import cn.dev33.satoken.stp.parameter.SaLogoutParameter;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token SSO 消息 处理器 - sso-server 处理 单点注销 的请求
* SSO 消息处理器 - sso-server 处理 单点注销 的请求
*
* @author click33
* @since 1.43.0
@ -52,24 +50,25 @@ public class SaSsoMessageSignoutHandle implements SaSsoMessageHandle {
* @return /
*/
public Object handle(SaSsoTemplate ssoTemplate, SaSsoMessage message) {
// 1获取对象
SaSsoServerTemplate ssoServerTemplate = (SaSsoServerTemplate) ssoTemplate;
ParamName paramName = ssoServerTemplate.paramName;
// 2判断当前是否开启了全局单点注销功能
if( ! ssoServerTemplate.getServerConfig().getIsSlo()) {
return SaResult.error("当前 sso-server 端未开启单点注销功能");
}
// 获取参数
SaRequest req = SaHolder.getRequest();
String loginId = req.getParam(paramName.loginId);
String deviceId = req.getParam(paramName.deviceId);
// 3获取参数
Object loginId = message.get(paramName.loginId);
String deviceId = message.getString(paramName.deviceId);
// step.2 单点注销
SaLogoutParameter logoutParameter = ssoServerTemplate.getStpLogic().createSaLogoutParameter()
.setDeviceId(deviceId);
// 4单点注销
SaLogoutParameter logoutParameter = ssoServerTemplate.getStpLogic().createSaLogoutParameter().setDeviceId(deviceId);
ssoServerTemplate.ssoLogout(loginId, logoutParameter);
// 响应
// 5响应
return SaResult.ok();
}

View File

@ -47,12 +47,9 @@ public class SaCheckTicketResult implements Serializable {
/** 此账号在认证中心的 loginId */
public Object centerId;
/** 从 sso-server 返回的所有参数 */
/** 从 sso-server 返回的原生所有参数 */
public SaResult result;
public SaCheckTicketResult() {
}
@Override
public String toString() {
return "SaCheckTicketResult{" +

View File

@ -21,7 +21,7 @@ import cn.dev33.satoken.sso.util.SaSsoConsts;
import java.io.Serializable;
/**
* Sa-Token SSO 应用信息
* Sa-Token SSO 应用信息注册在 SaSession 上的已登录应用信息列表
*
* @author click33
* @since 1.38.0
@ -45,13 +45,8 @@ public class SaSsoClientInfo implements Serializable {
*/
public String client;
// /**
// * 此次登录 token
// */
// public String tokenValue;
/**
* 单点注销回调url
* 单点注销回调 url
*/
public String sloCallbackUrl;
@ -80,6 +75,8 @@ public class SaSsoClientInfo implements Serializable {
}
// get set
/**
* 获取 client 登录模式1=模式一2=模式二3=模式三
*
@ -120,26 +117,6 @@ public class SaSsoClientInfo implements Serializable {
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
*
@ -205,7 +182,6 @@ public class SaSsoClientInfo implements Serializable {
return "SaSsoClientModel{" +
"mode=" + mode +
", client='" + client + '\'' +
// ", tokenValue='" + tokenValue + '\'' +
", sloCallbackUrl='" + sloCallbackUrl + '\'' +
", regTime=" + regTime +
", index=" + index +

View File

@ -37,11 +37,6 @@ public class TicketModel implements Serializable {
*/
public String client;
// /**
// * 设备 id
// */
// public String deviceId;
/**
* 对应 loginId
*/

View File

@ -32,7 +32,7 @@ public class ApiName {
/** SSO-Server端校验ticket 获取账号id */
public String ssoCheckTicket = "/sso/checkTicket";
/** SSO-Server端推送消息 */
/** SSO-Server端推送消息 */
public String ssoPushS = "/sso/pushS";
/** SSO-Server端获取userinfo */
@ -53,11 +53,11 @@ public class ApiName {
/** SSO-Client端单点注销的回调 */
public String ssoLogoutCall = "/sso/logoutCall";
/** SSO-Client端推送消息 */
/** SSO-Client端推送消息 */
public String ssoPushC = "/sso/pushC";
/**
* 批量修改path新增固定前缀
* 批量修改 path新增固定前缀
* @param prefix 示例值/sso-user/sso-admin
* @return 对象自身
*/
@ -77,7 +77,7 @@ public class ApiName {
}
/**
* 批量修改path替换掉 /sso 固定前缀
* 批量修改 path替换掉 /sso 固定前缀
* @param prefix 示例值/sso-user/sso-admin
* @return 对象自身
*/
@ -106,6 +106,7 @@ public class ApiName {
", ssoPushS='" + ssoPushS + '\'' +
", ssoUserinfo='" + ssoUserinfo + '\'' +
", ssoSignout='" + ssoSignout + '\'' +
", ssoIsLogin='" + ssoIsLogin + '\'' +
", ssoLogin='" + ssoLogin + '\'' +
", ssoLogout='" + ssoLogout + '\'' +
", ssoLogoutCall='" + ssoLogoutCall + '\'' +

View File

@ -23,40 +23,40 @@ package cn.dev33.satoken.sso.name;
*/
public class ParamName {
/** redirect参数名称 */
/** redirect 参数名称 */
public String redirect = "redirect";
/** ticket参数名称 */
/** ticket 参数名称 */
public String ticket = "ticket";
/** back参数名称 */
/** back 参数名称 */
public String back = "back";
/** mode参数名称 */
/** mode 参数名称 */
public String mode = "mode";
/** loginId参数名称 */
/** 账号 id */
public String loginId = "loginId";
/** client参数名称 */
/** client 应用标识 */
public String client = "client";
/** tokenName 参数 */
/** token 名称 */
public String tokenName = "tokenName";
/** tokenValue 参数 */
/** token */
public String tokenValue = "tokenValue";
/** deviceId 参数名称 */
/** 设备 id */
public String deviceId = "deviceId";
/** secretkey参数名称 */
/** 接口参数签名秘钥 */
public String secretkey = "secretkey";
/** Client端单点注销时-回调URL 参数名称 */
/** Client 端单点注销时 - 回调 URL 参数名称 */
public String ssoLogoutCall = "ssoLogoutCall";
/** 是否为超过 maxRegClient 的自动注销 */
/** 是否为超过 maxRegClient 触发的自动注销 */
public String autoLogout = "autoLogout";
public String name = "name";
@ -72,13 +72,8 @@ public class ParamName {
/** token 剩余有效期 参数名称 */
public String remainTokenTimeout = "remainTokenTimeout";
/** singleDeviceIdLogout 参数 */
/** 是否单设备 id 注销 */
public String singleDeviceIdLogout = "singleDeviceIdLogout";
public String isLogin = "isLogin";
public String authUrl = "authUrl";
public String redirectUrl = "redirectUrl";
public String currSsoLoginUrl = "currSsoLoginUrl";
}

View File

@ -70,22 +70,22 @@ public class SaSsoClientProcessor {
// ------------------ 路由分发 ------------------
// ---------- SSO-Client端登录地址
// sso-client登录地址
if(req.isPath(apiName.ssoLogin)) {
return ssoLogin();
}
// ---------- SSO-Client端单点注销
// sso-client单点注销
if(req.isPath(apiName.ssoLogout)) {
return ssoLogout();
}
// ---------- SSO-Client端接收消息推送
// sso-client接收消息推送
if(req.isPath(apiName.ssoPushC)) {
return ssoPushC();
}
// ---------- SSO-Client端单点注销的回调 [模式三]
// sso-client单点注销的回调
if(req.isPath(apiName.ssoLogoutCall) && cfg.getRegLogoutCall()) {
return ssoLogoutCall();
}
@ -101,55 +101,18 @@ public class SaSsoClientProcessor {
public Object ssoLogin() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaSsoClientConfig cfg = ssoClientTemplate.getClientConfig();
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
ApiName apiName = ssoClientTemplate.apiName;
ParamName paramName = ssoClientTemplate.paramName;
// 获取参数
String back = req.getParam(paramName.back, "/");
String ticket = req.getParam(paramName.ticket);
/*
* 此时有两种情况:
* 情况1ticket无值说明此请求是Client端访问需要重定向至SSO认证中心
* 情况2ticket有值说明此请求从SSO认证中心重定向而来需要根据ticket进行登录
* 情况1ticket 无值说明此请求是 sso-client 端访问需要重定向至 sso-server 认证中心
* 情况2ticket 有值说明此请求从 sso-server 认证中心重定向而来需要根据 ticket 进行登录
*/
if(ticket == null) {
// 如果当前Client端已经登录则无需访问SSO认证中心可以直接返回
if(stpLogic.isLogin()) {
return res.redirect(back);
}
// 获取当前项目的 sso 登录地址
// 全局配置了就是用全局的否则使用当前请求的地址
String currSsoLoginUrl;
if(SaFoxUtil.isNotEmpty(cfg.getCurrSsoLogin())) {
currSsoLoginUrl = cfg.getCurrSsoLogin();
} else {
currSsoLoginUrl = SaHolder.getRequest().getUrl();
}
// 构建url
String serverAuthUrl = ssoClientTemplate.buildServerAuthUrl(currSsoLoginUrl, back);
return res.redirect(serverAuthUrl);
return _goServerAuth();
} else {
// 1校验ticket获取 loginId
SaCheckTicketResult ctr = checkTicket(ticket, apiName.ssoLogin);
ctr.centerId = ctr.loginId;
ctr.loginId = ssoClientTemplate.strategy.convertCenterIdToLoginId.run(ctr.centerId);
// 2如果开发者自定义了ticket结果值处理函数则使用自定义的函数
if(ssoClientTemplate.strategy.ticketResultHandle != null) {
return ssoClientTemplate.strategy.ticketResultHandle.run(ctr, back);
}
// 3登录并重定向至back地址
stpLogic.login(ctr.loginId, new SaLoginParameter()
.setTimeout(ctr.remainTokenTimeout)
.setDeviceId(ctr.deviceId)
);
return res.redirect(back);
return _loginByTicket();
}
}
@ -162,9 +125,10 @@ public class SaSsoClientProcessor {
SaSsoClientConfig cfg = ssoClientTemplate.getClientConfig();
// 无论登录时选择的是模式二还是模式三
// 在注销时都应该按照模式三的方法通过 http 请求调用 sso-server 的单点注销接口来做到全端下线
// 在注销时都应该按照模式三的方法通过 http 请求调用 sso-server 的单点注销接口来做到全端下线
// 如果按照模式二的方法注销则会导致按照模式三登录的应用无法参与到单点注销环路中来
if(cfg.getIsSlo()) {
return ssoLogoutByMode3();
return _ssoLogoutByMode3();
}
// 默认返回
@ -192,63 +156,6 @@ public class SaSsoClientProcessor {
return ssoClientTemplate.handleMessage(message);
}
/**
* SSO-Client端单点注销 [模式二]
* @return 处理结果
*/
public Object ssoLogoutByMode2() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
// 开始处理
if(stpLogic.isLogin()) {
stpLogic.logout(stpLogic.getLoginId());
}
// 返回
return ssoLogoutBack(req, res);
}
/**
* SSO-Client端单点注销 [模式三]
* @return 处理结果
*/
public Object ssoLogoutByMode3() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
boolean singleDeviceIdLogout = req.isParam(ssoClientTemplate.paramName.singleDeviceIdLogout, "true");
// 如果未登录则无需注销
if( ! stpLogic.isLogin()) {
return ssoLogoutBack(req, res);
}
// 调用 sso-server 认证中心单点注销API
SaLogoutParameter logoutParameter = stpLogic.createSaLogoutParameter();
if(singleDeviceIdLogout) {
logoutParameter.setDeviceId(stpLogic.getLoginDeviceId());
}
Object centerId = ssoClientTemplate.strategy.convertLoginIdToCenterId.run(stpLogic.getLoginId());
SaSsoMessage message = ssoClientTemplate.buildSloMessage(centerId, logoutParameter);
SaResult result = ssoClientTemplate.pushMessageAsSaResult(message);
// 校验响应状态码
if(result.getCode() != null && SaResult.CODE_SUCCESS == result.getCode()) {
// 极端场景下sso-server 中心的单点注销可能并不会通知到此 client 所以这里需要再补一刀
if(stpLogic.isLogin()) {
stpLogic.logout();
}
return ssoLogoutBack(req, res);
} else {
// sso-server 回应的消息作为异常抛出
throw new SaSsoException(result.getMsg()).setCode(SaSsoErrorCode.CODE_30006);
}
}
/**
* SSO-Client端单点注销的回调 [模式三]
* @return 处理结果
@ -265,8 +172,6 @@ public class SaSsoClientProcessor {
Object loginId = req.getParamNotNull(paramName.loginId);
loginId = ssoClientTemplate.strategy.convertCenterIdToLoginId.run(loginId);
String deviceId = req.getParam(paramName.deviceId);
// String client = req.getParam(paramName.client);
// String autoLogout = req.getParam(paramName.autoLogout);
// 校验参数签名
if(ssoConfig.getIsCheckSign()) {
@ -283,7 +188,109 @@ public class SaSsoClientProcessor {
return SaResult.ok("单点注销回调成功");
}
// 工具方法
// 次级方法
/**
* 跳转去 sso-server 认证中心
* @return /
*/
public Object _goServerAuth() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaSsoClientConfig cfg = ssoClientTemplate.getClientConfig();
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
ParamName paramName = ssoClientTemplate.paramName;
// 获取参数
String back = req.getParam(paramName.back, "/");
// 如果当前 sso-client 端已经登录则无需访问 SSO 认证中心可以直接返回
if(stpLogic.isLogin()) {
return res.redirect(back);
}
// 获取当前项目的 sso 登录中转页地址形如http://sso-client.com/sso/login
// 全局配置了就是用全局的否则使用当前请求的地址
String currSsoLoginUrl = cfg.getCurrSsoLogin();
if(SaFoxUtil.isEmpty(currSsoLoginUrl)) {
currSsoLoginUrl = SaHolder.getRequest().getUrl();
}
// 构建最终授权地址 url形如http://sso-server.com/sso/auth?redirectUrl=http://sso-client.com/sso/login?back=http://sso-client.com
String serverAuthUrl = ssoClientTemplate.buildServerAuthUrl(currSsoLoginUrl, back);
return res.redirect(serverAuthUrl);
}
/**
* 根据认证中心回传的 ticket 进行登录
* @return /
*/
public Object _loginByTicket() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
ParamName paramName = ssoClientTemplate.paramName;
ApiName apiName = ssoClientTemplate.apiName;
// 获取参数
String back = req.getParam(paramName.back, "/");
String ticket = req.getParam(paramName.ticket);
// 1校验 ticket获取 loginId 等数据
SaCheckTicketResult ctr = checkTicket(ticket, apiName.ssoLogin);
ctr.centerId = ctr.loginId;
ctr.loginId = ssoClientTemplate.strategy.convertCenterIdToLoginId.run(ctr.centerId);
// 2如果开发者自定义了 ticket 结果值处理函数则使用自定义的函数
if(ssoClientTemplate.strategy.ticketResultHandle != null) {
return ssoClientTemplate.strategy.ticketResultHandle.run(ctr, back);
}
// 3登录并重定向至back地址
stpLogic.login(ctr.loginId, new SaLoginParameter()
.setTimeout(ctr.remainTokenTimeout)
.setDeviceId(ctr.deviceId)
);
return res.redirect(back);
}
/**
* SSO-Client端单点注销 [模式三]
* @return 处理结果
*/
public Object _ssoLogoutByMode3() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
boolean singleDeviceIdLogout = req.isParam(ssoClientTemplate.paramName.singleDeviceIdLogout, "true");
// 如果未登录则无需注销
if( ! stpLogic.isLogin()) {
return _ssoLogoutBack(req, res);
}
// sso-server 认证中心推送消息单点注销
SaLogoutParameter logoutParameter = stpLogic.createSaLogoutParameter();
if(singleDeviceIdLogout) {
logoutParameter.setDeviceId(stpLogic.getLoginDeviceId());
}
Object centerId = ssoClientTemplate.strategy.convertLoginIdToCenterId.run(stpLogic.getLoginId());
SaSsoMessage message = ssoClientTemplate.buildSloMessage(centerId, logoutParameter);
SaResult result = ssoClientTemplate.pushMessageAsSaResult(message);
// 如果 sso-server 响应的状态码非200代表业务失败将回应的 msg 字段作为异常抛出
if(result.getCode() == null || SaResult.CODE_SUCCESS != result.getCode()) {
throw new SaSsoException(result.getMsg()).setCode(SaSsoErrorCode.CODE_30006);
}
// 极端场景下sso-server 中心的单点注销可能并不会通知到当前 client 所以这里需要再补一刀
if(stpLogic.isLogin()) {
stpLogic.logout(logoutParameter);
}
return _ssoLogoutBack(req, res);
}
/**
* 封装校验ticket取出loginId如果 ticket 无效则抛出异常 适用于模式二或模式三
@ -294,70 +301,90 @@ public class SaSsoClientProcessor {
*/
public SaCheckTicketResult checkTicket(String ticket, String currUri) {
SaSsoClientConfig cfg = ssoClientTemplate.getClientConfig();
// 两种模式
// isHttp=true模式三使用 http 请求从认证中心校验ticket
// isHttp=false模式二直连 redis 中校验 ticket
if(cfg.getIsHttp()) {
return _checkTicketByHttp(ticket, currUri);
} else {
return _checkTicketByRedis(ticket);
}
}
/**
* 校验 tickethttp 请求方式
* @param ticket /
* @param currUri /
* @return /
*/
public SaCheckTicketResult _checkTicketByHttp(String ticket, String currUri) {
SaSsoClientConfig cfg = ssoClientTemplate.getClientConfig();
ApiName apiName = ssoClientTemplate.apiName;
ParamName paramName = ssoClientTemplate.paramName;
// --------- 两种模式
if(cfg.getIsHttp()) {
// q1使用模式三使用 http 请求从认证中心校验ticket
// 计算当前 sso-client 的单点注销回调地址
String ssoLogoutCall = null;
if(cfg.getRegLogoutCall()) {
// 如果配置了回调地址就使用配置的值
if(SaFoxUtil.isNotEmpty(cfg.getCurrSsoLogoutCall())) {
ssoLogoutCall = cfg.getCurrSsoLogoutCall();
}
// 如果提供了当前 uri则根据此值来计算
else if(SaFoxUtil.isNotEmpty(currUri)) {
ssoLogoutCall = SaHolder.getRequest().getUrl().replace(currUri, apiName.ssoLogoutCall);
}
// 否则视为不注册单点注销回调地址
else {
}
// 计算当前 sso-client 的单点注销回调地址
String ssoLogoutCall = null;
if(cfg.getRegLogoutCall()) {
// 如果配置了回调地址就使用配置的值
if(SaFoxUtil.isNotEmpty(cfg.getCurrSsoLogoutCall())) {
ssoLogoutCall = cfg.getCurrSsoLogoutCall();
}
// 发起请求
SaSsoMessage message = ssoClientTemplate.buildCheckTicketMessage(ticket, ssoLogoutCall);
SaResult result = ssoClientTemplate.pushMessageAsSaResult(message);
// 校验
if(result.getCode() != null && result.getCode() == SaResult.CODE_SUCCESS) {
SaCheckTicketResult ctr = new SaCheckTicketResult();
ctr.loginId = result.get(paramName.loginId);
ctr.tokenValue = result.get(paramName.tokenValue, String.class);
ctr.deviceId = result.get(paramName.deviceId, String.class);
ctr.remainTokenTimeout = result.get(paramName.remainTokenTimeout, Long.class);
ctr.remainSessionTimeout = result.get(paramName.remainSessionTimeout, Long.class);
ctr.result = result;
return ctr;
} else {
// sso-server 回应的消息作为异常抛出
throw new SaSsoException(result.getMsg()).setCode(SaSsoErrorCode.CODE_30005);
// 如果提供了当前 uri则根据此值来计算
else if(SaFoxUtil.isNotEmpty(currUri)) {
ssoLogoutCall = SaHolder.getRequest().getUrl().replace(currUri, apiName.ssoLogoutCall);
}
// 否则视为不注册单点注销回调地址
else {
}
} else {
// q2使用模式二直连Redis校验ticket
// 注意此处调用了 SaSsoServerProcessor 处理器里的方法
// 这意味着如果你的 sso-server 端重写了 SaSsoServerProcessor 里的部分方法
// 而在当前 sso-client 没有按照相应格式重写 SaSsoClientProcessor 里的方法
// 可能会导致调用失败注意是可能而非一定
// 解决方案为在当前 sso-client 端也按照 sso-server 端的格式重写 SaSsoClientProcessor 里的方法
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
TicketModel ticketModel = SaSsoServerProcessor.instance.ssoServerTemplate.checkTicketParamAndDelete(ticket, ssoClientTemplate.getClient());
SaCheckTicketResult ctr = new SaCheckTicketResult();
ctr.loginId = ticketModel.getLoginId();
ctr.tokenValue = ticketModel.getTokenValue();
ctr.deviceId = stpLogic.getLoginDeviceIdByToken(ticketModel.getTokenValue());
ctr.remainTokenTimeout = stpLogic.getTokenTimeout(ticketModel.getTokenValue());
ctr.remainSessionTimeout = stpLogic.getSessionTimeoutByLoginId(ticketModel.getLoginId());
ctr.result = null;
return ctr;
}
// 发起请求
SaSsoMessage message = ssoClientTemplate.buildCheckTicketMessage(ticket, ssoLogoutCall);
SaResult result = ssoClientTemplate.pushMessageAsSaResult(message);
// 如果 sso-server 响应的状态码非200代表业务失败将回应的 msg 字段作为异常抛出
if(result.getCode() == null || result.getCode() != SaResult.CODE_SUCCESS) {
throw new SaSsoException(result.getMsg()).setCode(SaSsoErrorCode.CODE_30005);
}
// 构建返回结果
SaCheckTicketResult ctr = new SaCheckTicketResult();
ctr.loginId = result.get(paramName.loginId);
ctr.tokenValue = result.get(paramName.tokenValue, String.class);
ctr.deviceId = result.get(paramName.deviceId, String.class);
ctr.remainTokenTimeout = result.get(paramName.remainTokenTimeout, Long.class);
ctr.remainSessionTimeout = result.get(paramName.remainSessionTimeout, Long.class);
ctr.result = result;
return ctr;
}
/**
* 校验 ticket直连 redis 方式
* @param ticket /
* @return /
*/
public SaCheckTicketResult _checkTicketByRedis(String ticket) {
// 直连 redis 校验 ticket
// 注意此处调用了 SaSsoServerProcessor 处理器里的方法
// 这意味着如果你的 sso-server 端重写了 SaSsoServerProcessor 里的部分方法
// 而在当前 sso-client 没有按照相应格式重写 SaSsoClientProcessor 里的方法
// 可能会导致调用失败注意是可能而非一定主要取决于你是否改变了数据读写格式
// 解决方案为在当前 sso-client 端也按照 sso-server 端的格式重写 SaSsoClientProcessor 里的方法
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
TicketModel ticketModel = SaSsoServerProcessor.instance.ssoServerTemplate.checkTicketParamAndDelete(ticket, ssoClientTemplate.getClient());
SaCheckTicketResult ctr = new SaCheckTicketResult();
ctr.loginId = ticketModel.getLoginId();
ctr.tokenValue = ticketModel.getTokenValue();
ctr.deviceId = stpLogic.getLoginDeviceIdByToken(ticketModel.getTokenValue());
ctr.remainTokenTimeout = stpLogic.getTokenTimeout(ticketModel.getTokenValue());
ctr.remainSessionTimeout = stpLogic.getSessionTimeoutByLoginId(ticketModel.getLoginId());
ctr.result = null;
return ctr;
}
/**
@ -366,10 +393,8 @@ public class SaSsoClientProcessor {
* @param res SaResponse对象
* @return 返回结果
*/
public Object ssoLogoutBack(SaRequest req, SaResponse res) {
public Object _ssoLogoutBack(SaRequest req, SaResponse res) {
return SaSsoProcessorHelper.ssoLogoutBack(req, res, ssoClientTemplate.paramName);
}
}

View File

@ -17,8 +17,8 @@ package cn.dev33.satoken.sso.processor;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.sso.util.SaSsoConsts;
import cn.dev33.satoken.sso.name.ParamName;
import cn.dev33.satoken.sso.util.SaSsoConsts;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult;

View File

@ -57,13 +57,13 @@ public class SaSsoServerProcessor {
/**
* 分发 Server 端所有请求
*
* @return 处理结果
*/
public Object dister() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaSsoServerConfig cfg = ssoServerTemplate.getServerConfig();
ApiName apiName = ssoServerTemplate.apiName;
// ------------------ 路由分发 ------------------
@ -104,36 +104,44 @@ public class SaSsoServerProcessor {
StpLogic stpLogic = ssoServerTemplate.getStpLogic();
ParamName paramName = ssoServerTemplate.paramName;
// ---------- 此处有两种情况分开处理
// ---- 情况1在SSO认证中心尚未登录需要先去登录
// 两种情况
// 情况1 SSO 认证中心尚未登录需要显示登录视图去登录
// 情况2 SSO 认证中心已经登录需要重定向回 Client
// 情况1显示登录视图
if( ! stpLogic.isLogin()) {
return ssoServerTemplate.strategy.notLoginView.get();
}
// ---- 情况2在SSO认证中心已经登录需要重定向回 Client 而这又分为两种方式
// 情况2开始跳转
String mode = req.getParam(paramName.mode, SaSsoConsts.MODE_TICKET);
String redirect = req.getParam(paramName.redirect);
String client = req.getParam(paramName.client);
// redirect 为空则选择 homeRoute homeRoute 也为空则抛出异常
if(SaFoxUtil.isEmpty(redirect)) {
if(SaFoxUtil.isEmpty(cfg.getHomeRoute())) {
throw new SaSsoException("未指定 redirect 参数,也未配置 homeRoute 路由,无法完成重定向操作").setCode(SaSsoErrorCode.CODE_30014);
}
ssoServerTemplate.strategy.jumpToRedirectUrlNotice.run(cfg.getHomeRoute());
return res.redirect(cfg.getHomeRoute());
}
// 构建最终重定向地址
String redirectUrl = SaSugar.get(() -> {
// 方式1直接重定向回Client端 (mode=simple)
// redirect 参数为空说明用户并不是从 client 重定向来的而是直接访问的 http://sso-server.com/sso/auth 地址
// 此时需要跳转到配置的 homeRoute 路由上
// homeRoute 也为空则没有明确的跳转地址了需要抛出异常
if(SaFoxUtil.isEmpty(redirect)) {
if(SaFoxUtil.isEmpty(cfg.getHomeRoute())) {
throw new SaSsoException("未指定 redirect 参数,也未配置 homeRoute 路由,无法完成重定向操作").setCode(SaSsoErrorCode.CODE_30014);
}
return cfg.getHomeRoute();
}
// 方式1直接重定向回Client端 (mode=simple一般是模式一)
if(mode.equals(SaSsoConsts.MODE_SIMPLE)) {
ssoServerTemplate.checkRedirectUrl(client, redirect);
return redirect;
} else {
// 方式2带着 ticket 参数重定向回Client端 (mode=ticket)
// 方式2带着 ticket 参数重定向回Client端 (mode=ticket一般是模式二)
// 构建并跳转
String _redirectUrl = ssoServerTemplate.buildRedirectUrl(client, redirect, stpLogic.getLoginId(), stpLogic.getTokenValue());
// 构建成功说明 redirect 地址合法此时需要更新一下该账号的Session有效期
// 构建成功说明 redirect 地址合法此时需要更新一下当前 token 有效期
if(cfg.getAutoRenewTimeout()) {
stpLogic.renewTimeout(stpLogic.getConfigOrGlobal().getTimeout());
}
@ -151,13 +159,14 @@ public class SaSsoServerProcessor {
* @return 处理结果
*/
public Object ssoDoLogin() {
// 获取对象
// 获取参数
SaRequest req = SaHolder.getRequest();
SaSsoServerConfig cfg = ssoServerTemplate.getServerConfig();
ParamName paramName = ssoServerTemplate.paramName;
String name = req.getParam(paramName.name);
String pwd = req.getParam(paramName.pwd);
// 处理
return ssoServerTemplate.strategy.doLoginHandle.apply(req.getParam(paramName.name), req.getParam(paramName.pwd));
return ssoServerTemplate.strategy.doLoginHandle.apply(name, pwd);
}
/**
@ -168,14 +177,15 @@ public class SaSsoServerProcessor {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
Object loginId = ssoServerTemplate.getStpLogic().getLoginIdDefaultNull();
StpLogic stpLogic = ssoServerTemplate.getStpLogic();
Object loginId = stpLogic.getLoginIdDefaultNull();
boolean singleDeviceIdLogout = req.isParam(ssoServerTemplate.paramName.singleDeviceIdLogout, "true");
// 单点注销
if(SaFoxUtil.isNotEmpty(loginId)) {
SaLogoutParameter logoutParameter = ssoServerTemplate.getStpLogic().createSaLogoutParameter();
SaLogoutParameter logoutParameter = stpLogic.createSaLogoutParameter();
if(singleDeviceIdLogout) {
logoutParameter.setDeviceId(ssoServerTemplate.getStpLogic().getLoginDeviceId());
logoutParameter.setDeviceId(stpLogic.getLoginDeviceId());
}
ssoServerTemplate.ssoLogout(loginId, logoutParameter);
}
@ -202,7 +212,7 @@ public class SaSsoServerProcessor {
return SaResult.error("无效 client 标识:" + client);
}
// 3校验签名
// 3校验参数签名
Map<String, String> paramMap = req.getParamMap();
if(ssoServerConfig.getIsCheckSign()) {
ssoServerTemplate.getSignTemplate(client).checkParamMap(paramMap);
@ -210,10 +220,10 @@ public class SaSsoServerProcessor {
SaSsoManager.printNoCheckSignWarningByRuntime();
}
// 处理消息
// 4处理消息
SaSsoMessage message = new SaSsoMessage(paramMap);
if( ! ssoServerTemplate.messageHolder.hasHandle(message.getType())) {
return SaResult.error("未能找到消息处理器: " + message.getType());
return SaResult.error("未能找到消息处理器" + message.getType());
}
return ssoServerTemplate.handleMessage(message);
}

View File

@ -19,6 +19,9 @@ import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.fun.SaParamRetFunction;
import cn.dev33.satoken.sso.function.SendHttpFunction;
import cn.dev33.satoken.sso.function.TicketResultHandleFunction;
import cn.dev33.satoken.util.SaResult;
import java.util.Map;
/**
* Sa-Token SSO Client 相关策略
@ -62,4 +65,16 @@ public class SaSsoClientStrategy {
return loginId;
};
/**
* 发送 Http 请求并将响应结果转换为 SaResult
*
* @param url 请求地址
* @return 返回的结果
*/
public SaResult requestAsSaResult(String url) {
String body = sendHttp.apply(url);
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(body);
return new SaResult(map);
}
}

View File

@ -23,6 +23,8 @@ import cn.dev33.satoken.sso.function.NotLoginViewFunction;
import cn.dev33.satoken.sso.function.SendHttpFunction;
import cn.dev33.satoken.util.SaResult;
import java.util.Map;
/**
* Sa-Token SSO Server 相关策略
*
@ -66,4 +68,16 @@ public class SaSsoServerStrategy {
return result;
};
/**
* 发送 Http 请求并将响应结果转换为 SaResult
*
* @param url 请求地址
* @return 返回的结果
*/
public SaResult requestAsSaResult(String url) {
String body = sendHttp.apply(url);
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(body);
return new SaResult(map);
}
}

View File

@ -33,7 +33,7 @@ import cn.dev33.satoken.util.SaResult;
import java.util.Map;
/**
* Sa-Token SSO 模板方法类 Client端
* SSO 模板方法类 Client端
*
* @author click33
* @since 1.38.0
@ -50,10 +50,11 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
}
// ------------------- SSO 模式三相关 -------------------
// ------------------- getData 相关 -------------------
/**
* 根据配置的 getData 地址查询数据
*
* @param paramMap 查询参数
* @return 查询结果
*/
@ -64,6 +65,7 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
/**
* 根据自定义 path 地址查询数据 此方法需要配置 sa-token.sso.server-url 地址
*
* @param path 自定义 path
* @param paramMap 查询参数
* @return 查询结果
@ -73,44 +75,6 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
return strategy.sendHttp.apply(url);
}
// ---------------------- 构建URL ----------------------
/**
* 构建URLServer端 单点登录地址
* @param clientLoginUrl Client端登录地址
* @param back 回调路径
* @return [SSO-Server端-认证地址 ]
*/
public String buildServerAuthUrl(String clientLoginUrl, String back) {
SaSsoClientConfig ssoConfig = getClientConfig();
// 服务端认证地址
String serverUrl = ssoConfig.splicingAuthUrl();
// 拼接客户端标识
String client = getClient();
if(SaFoxUtil.isNotEmpty(client)) {
serverUrl = SaFoxUtil.joinParam(serverUrl, paramName.client, client);
}
// 对back地址编码
back = (back == null ? "" : back);
back = SaFoxUtil.encodeUrl(back);
// 开始拼接 sso 统一认证地址形如serverAuthUrl = http://xxx.com?redirectUrl=xxx.com?back=xxx.com
/*
* 部分 Servlet 版本 request.getRequestURL() 返回的 url 带有 query 参数形如http://domain.com?id=1
* 如果不加判断会造成最终生成的 serverAuthUrl 带有双 back 参数 这个 if 判断正是为了解决此问题
*/
if( ! clientLoginUrl.contains(paramName.back + "=") ) {
clientLoginUrl = SaFoxUtil.joinParam(clientLoginUrl, paramName.back, back);
}
// 返回
return SaFoxUtil.joinParam(serverUrl, paramName.redirect, clientLoginUrl);
}
/**
* 构建URLServer端 getData 地址带签名等参数
* @param paramMap 查询参数
@ -146,55 +110,49 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
return SaFoxUtil.joinParam(url, signParamsStr);
}
/**
* 构建消息校验 ticket
*
* @param ticket ticket码
* @param ssoLogoutCallUrl 单点注销时的回调URL
* @return 构建完毕的URL
*/
public SaSsoMessage buildCheckTicketMessage(String ticket, String ssoLogoutCallUrl) {
SaSsoClientConfig ssoConfig = getClientConfig();
SaSsoMessage message = new SaSsoMessage();
message.setType(SaSsoConsts.MESSAGE_CHECK_TICKET);
message.set(paramName.client, getClient());
message.set(paramName.ticket, ticket);
message.set(paramName.ssoLogoutCall, ssoLogoutCallUrl);
return message;
}
// ---------------------- 构建交互地址 ----------------------
/**
* 构建消息单点注销
*
* @param loginId 要注销的账号 id
* @param logoutParameter 单点注销
* @return 单点注销URL
* 构建URLServer端 单点登录授权地址
* <br/> 形如http://sso-server.com/sso/auth?redirectUrl=http://sso-client.com/sso/login?back=http://sso-client.com
* @param clientLoginUrl Client端登录地址
* @param back 回调路径
* @return [SSO-Server端-认证地址 ]
*/
public SaSsoMessage buildSloMessage(Object loginId, SaLogoutParameter logoutParameter) {
public String buildServerAuthUrl(String clientLoginUrl, String back) {
SaSsoClientConfig ssoConfig = getClientConfig();
SaSsoMessage message = new SaSsoMessage();
message.setType(SaSsoConsts.MESSAGE_SIGNOUT);
message.set(paramName.client, getClient());
message.set(paramName.loginId, loginId);
message.set(paramName.deviceId, logoutParameter.getDeviceId());
return message;
// 服务端认证地址
String serverUrl = ssoConfig.splicingAuthUrl();
// 拼接客户端标识
String client = getClient();
if(SaFoxUtil.isNotEmpty(client)) {
serverUrl = SaFoxUtil.joinParam(serverUrl, paramName.client, client);
}
// 对back地址编码
back = (back == null ? "" : back);
back = SaFoxUtil.encodeUrl(back);
// 开始拼接 sso 统一认证地址形如serverAuthUrl = http://xxx.com?redirectUrl=xxx.com?back=xxx.com
/*
* 部分 Servlet 版本 request.getRequestURL() 返回的 url 带有 query 参数形如http://domain.com?id=1
* 如果不加判断会造成最终生成的 serverAuthUrl 带有双 back 参数 这个 if 判断正是为了解决此问题
*/
if( ! clientLoginUrl.contains(paramName.back + "=") ) {
clientLoginUrl = SaFoxUtil.joinParam(clientLoginUrl, paramName.back, back);
}
// 返回
return SaFoxUtil.joinParam(serverUrl, paramName.redirect, clientLoginUrl);
}
// ------------------- 消息推送 -------------------
/**
* 发送 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 推送消息
*
@ -230,6 +188,40 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
return new SaResult(map);
}
/**
* 构建消息校验 ticket
*
* @param ticket ticket码
* @param ssoLogoutCallUrl 单点注销时的回调URL
* @return 构建完毕的URL
*/
public SaSsoMessage buildCheckTicketMessage(String ticket, String ssoLogoutCallUrl) {
SaSsoClientConfig ssoConfig = getClientConfig();
SaSsoMessage message = new SaSsoMessage();
message.setType(SaSsoConsts.MESSAGE_CHECK_TICKET);
message.set(paramName.client, getClient());
message.set(paramName.ticket, ticket);
message.set(paramName.ssoLogoutCall, ssoLogoutCallUrl);
return message;
}
/**
* 构建消息单点注销
*
* @param loginId 要注销的账号 id
* @param logoutParameter 单点注销
* @return 单点注销URL
*/
public SaSsoMessage buildSloMessage(Object loginId, SaLogoutParameter logoutParameter) {
SaSsoClientConfig ssoConfig = getClientConfig();
SaSsoMessage message = new SaSsoMessage();
message.setType(SaSsoConsts.MESSAGE_SIGNOUT);
message.set(paramName.client, getClient());
message.set(paramName.loginId, loginId);
message.set(paramName.deviceId, logoutParameter.getDeviceId());
return message;
}
// ------------------- Bean 对象获取 -------------------

View File

@ -0,0 +1,127 @@
/*
* 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.template;
import cn.dev33.satoken.sso.message.SaSsoMessage;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
import cn.dev33.satoken.stp.parameter.SaLogoutParameter;
import cn.dev33.satoken.util.SaResult;
import java.util.Map;
/**
* SSO 模板方法类 Client端
*
* @author click33
* @since 1.38.0
*/
public class SaSsoClientUtil extends SaSsoTemplate {
private SaSsoClientUtil() {
}
/**
* 返回底层使用的 SaSsoClientTemplate 对象
* @return /
*/
public static SaSsoClientTemplate getSsoTemplate() {
return SaSsoClientProcessor.instance.ssoClientTemplate;
}
// ------------------- getData 相关 -------------------
/**
* 根据配置的 getData 地址查询数据
*
* @param paramMap 查询参数
* @return 查询结果
*/
public static Object getData(Map<String, Object> paramMap) {
return SaSsoClientProcessor.instance.ssoClientTemplate.getData(paramMap);
}
/**
* 根据自定义 path 地址查询数据 此方法需要配置 sa-token.sso.server-url 地址
*
* @param path 自定义 path
* @param paramMap 查询参数
* @return 查询结果
*/
public static Object getData(String path, Map<String, Object> paramMap) {
return SaSsoClientProcessor.instance.ssoClientTemplate.getData(path, paramMap);
}
// ---------------------- 构建交互地址 ----------------------
/**
* 构建URLServer端 单点登录授权地址
* <br/> 形如http://sso-server.com/sso/auth?redirectUrl=http://sso-client.com/sso/login?back=http://sso-client.com
* @param clientLoginUrl Client端登录地址
* @param back 回调路径
* @return [SSO-Server端-认证地址 ]
*/
public static String buildServerAuthUrl(String clientLoginUrl, String back) {
return SaSsoClientProcessor.instance.ssoClientTemplate.buildServerAuthUrl(clientLoginUrl, back);
}
// ------------------- 消息推送 -------------------
/**
* sso-server 推送消息
*
* @param message /
* @return /
*/
public static String pushMessage(SaSsoMessage message) {
return SaSsoClientProcessor.instance.ssoClientTemplate.pushMessage(message);
}
/**
* sso-server 推送消息并将返回值转为 SaResult
*
* @param message /
* @return /
*/
public static SaResult pushMessageAsSaResult(SaSsoMessage message) {
return SaSsoClientProcessor.instance.ssoClientTemplate.pushMessageAsSaResult(message);
}
/**
* 构建消息校验 ticket
*
* @param ticket ticket码
* @param ssoLogoutCallUrl 单点注销时的回调URL
* @return 构建完毕的URL
*/
public static SaSsoMessage buildCheckTicketMessage(String ticket, String ssoLogoutCallUrl) {
return SaSsoClientProcessor.instance.ssoClientTemplate.buildCheckTicketMessage(ticket, ssoLogoutCallUrl);
}
/**
* 构建消息单点注销
*
* @param loginId 要注销的账号 id
* @param logoutParameter 单点注销
* @return 单点注销URL
*/
public static SaSsoMessage buildSloMessage(Object loginId, SaLogoutParameter logoutParameter) {
return SaSsoClientProcessor.instance.ssoClientTemplate.buildSloMessage(loginId, logoutParameter);
}
}

View File

@ -39,7 +39,7 @@ import cn.dev33.satoken.util.SaResult;
import java.util.*;
/**
* Sa-Token SSO 模板方法类 Server端
* SSO 模板方法类 Server端
*
* @author click33
* @since 1.38.0
@ -58,40 +58,17 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
// ---------------------- Ticket 操作 ----------------------
// 增删改
/**
* 保存 Ticket
* @param ticketModel /
*/
public void saveTicket(TicketModel ticketModel) {
long ticketTimeout = getServerConfig().getTicketTimeout();
SaManager.getSaTokenDao().setObject(splicingTicketSaveKey(ticketModel.getTicket()), ticketModel, ticketTimeout);
SaManager.getSaTokenDao().setObject(splicingTicketModelSaveKey(ticketModel.getTicket()), ticketModel, ticketTimeout);
}
/**
* 保存 Ticket 索引 id 反查 ticket
*
* @param client 应用端
* @param ticket ticket码
* @param loginId 账号id
*/
public void saveTicketIndex(String client, Object loginId, String ticket) {
long ticketTimeout = getServerConfig().getTicketTimeout();
SaManager.getSaTokenDao().set(splicingTicketIndexKey(client, loginId), String.valueOf(ticket), ticketTimeout);
}
// /**
// * 保存 Ticket 关联的 client
// * @param ticket ticket码
// * @param client 客户端标识
// */
// public void saveTicketToClient(String ticket, String client) {
// if(SaFoxUtil.isEmpty(client)) {
// return;
// }
// long ticketTimeout = getServerConfig().getTicketTimeout();
// SaManager.getSaTokenDao().set(splicingTicketToClientSaveKey(ticket), client, ticketTimeout);
// }
/**
* 删除 Ticket
* @param ticket Ticket码
@ -100,36 +77,59 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
if(ticket == null) {
return;
}
SaManager.getSaTokenDao().deleteObject(splicingTicketSaveKey(ticket));
SaManager.getSaTokenDao().deleteObject(splicingTicketModelSaveKey(ticket));
}
/**
* 删除 Ticket索引
* 根据参数创建一个 ticket
*
* @param client 应用标识
* @param loginId 账号id
* @param client 客户端标识
* @param loginId 账号 id
* @param tokenValue 会话 Token
* @return Ticket码
*/
public void deleteTicketIndex(String client, Object loginId) {
if(loginId == null) {
return;
}
SaManager.getSaTokenDao().delete(splicingTicketIndexKey(client, loginId));
public TicketModel createTicket(String client, Object loginId, String tokenValue) {
TicketModel ticketModel = new TicketModel();
ticketModel.setTicket(randomTicket(loginId));
ticketModel.setClient(client);
ticketModel.setLoginId(loginId);
ticketModel.setTokenValue(tokenValue);
return ticketModel;
}
// /**
// * 删除 Ticket 关联的 client
// *
// * @param ticket Ticket码
// */
// public void deleteTicketToClient(String ticket) {
// if(ticket == null) {
// return;
// }
// SaManager.getSaTokenDao().delete(splicingTicketToClientSaveKey(ticket));
// }
/**
* 根据参数创建一个 ticket 并保存
*
* @param client 客户端标识
* @param loginId 账号 id
* @param tokenValue 会话 Token
* @return Ticket码
*/
public String createTicketAndSave(String client, Object loginId, String tokenValue) {
// 创建
TicketModel ticketModel = createTicket(client, loginId, tokenValue);
// 保存
saveTicket(ticketModel);
saveTicketIndex(client, loginId, ticketModel.getTicket());
// 返回
return ticketModel.getTicket();
}
/**
* 查询 ticket 如果 ticket 码无效则返回 null
* 随机一个 Ticket
* @param loginId 账号id
* @return Ticket
*/
public String randomTicket(Object loginId) {
return SaFoxUtil.getRandomString(64);
}
//
/**
* 查询 ticket 如果 ticket 无效则返回 null
*
* @param ticket Ticket码
* @return 账号id
@ -138,7 +138,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
if(SaFoxUtil.isEmpty(ticket)) {
return null;
}
return SaManager.getSaTokenDao().getObject(splicingTicketSaveKey(ticket), TicketModel.class);
return SaManager.getSaTokenDao().getObject(splicingTicketModelSaveKey(ticket), TicketModel.class);
}
/**
@ -165,57 +165,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
return SaFoxUtil.getValueByType(getLoginId(ticket), cs);
}
/**
* 查询 指定 clientloginId 其所属的 ticket
*
* @param client 应用
* @param loginId 账号id
* @return Ticket值
*/
public String getTicketValue(String client, Object loginId) {
if(loginId == null) {
return null;
}
return SaManager.getSaTokenDao().get(splicingTicketIndexKey(client, loginId));
}
// /**
// * 查询 ticket 关联的 client如果 ticket 码无效则返回 null
// * @param ticket Ticket码
// * @return 账号id
// */
// public String getTicketToClient(String ticket) {
// if(SaFoxUtil.isEmpty(ticket)) {
// return null;
// }
// return SaManager.getSaTokenDao().get(splicingTicketToClientSaveKey(ticket));
// }
//
/**
* 根据参数创建一个 ticket
*
* @param client 客户端标识
* @param loginId 账号 id
* @param tokenValue 会话 Token
* @return Ticket码
*/
public String createTicket(String client, Object loginId, String tokenValue) {
// 创建 Ticket
String ticket = randomTicket(loginId);
TicketModel ticketModel = new TicketModel();
ticketModel.setTicket(ticket);
ticketModel.setClient(client);
ticketModel.setLoginId(loginId);
ticketModel.setTokenValue(tokenValue);
// 保存 Ticket
saveTicket(ticketModel);
saveTicketIndex(client, loginId, ticket);
// 返回 Ticket
return ticket;
}
// 校验
/**
* 校验 Ticket无效 ticket 会抛出异常
@ -271,13 +221,45 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
return ticketModel;
}
// ticket 索引
/**
* 随机一个 Ticket码
* 保存 Ticket 索引 id 反查 ticket
*
* @param client 应用端
* @param ticket ticket码
* @param loginId 账号id
* @return Ticket码
*/
public String randomTicket(Object loginId) {
return SaFoxUtil.getRandomString(64);
public void saveTicketIndex(String client, Object loginId, String ticket) {
long ticketTimeout = getServerConfig().getTicketTimeout();
SaManager.getSaTokenDao().set(splicingTicketIndexKey(client, loginId), String.valueOf(ticket), ticketTimeout);
}
/**
* 删除 Ticket 索引
*
* @param client 应用标识
* @param loginId 账号id
*/
public void deleteTicketIndex(String client, Object loginId) {
if(loginId == null) {
return;
}
SaManager.getSaTokenDao().delete(splicingTicketIndexKey(client, loginId));
}
/**
* 查询 指定 clientloginId 其所属的 ticket
*
* @param client 应用
* @param loginId 账号id
* @return Ticket值
*/
public String getTicketValue(String client, Object loginId) {
if(loginId == null) {
return null;
}
return SaManager.getSaTokenDao().get(splicingTicketIndexKey(client, loginId));
}
@ -289,8 +271,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
* @return /
*/
public List<SaSsoClientModel> getClients() {
Map<String, SaSsoClientModel> clients = getServerConfig().getClients();
return new ArrayList<>(clients.values());
return new ArrayList<>(getServerConfig().getClients().values());
}
/**
@ -351,7 +332,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
List<SaSsoClientModel> list = new ArrayList<>();
List<SaSsoClientModel> clients = getClients();
for(SaSsoClientModel scm : clients) {
if (scm.isValidNoticeUrl()) {
if (scm.getIsPush()) {
list.add(scm);
}
}
@ -379,14 +360,15 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
deleteTicket(getTicketValue(client, loginId));
// 创建 新Ticket
String ticket = createTicket(client, loginId, tokenValue);
String ticket = createTicketAndSave(client, loginId, tokenValue);
// 构建 授权重定向地址 Server端 根据此地址向 Client端 下放Ticket
// 构建 授权重定向地址 Server端 根据此地址向 Client端 下放 Ticket
return SaFoxUtil.joinParam(encodeBackParam(redirect), paramName.ticket, ticket);
}
/**
* 对url中的back参数进行URL编码, 解决超链接重定向后参数丢失的bug
* url 中的 back 参数进行 URL 编码, 解决超链接重定向后参数丢失的 bug
*
* @param url url
* @return 编码过后的url
*/
@ -412,7 +394,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
}
/**
* 校验重定向url合法性
* 校验重定向 url 合法性
*
* @param client 应用标识
* @param url 下放ticket的url地址
@ -513,7 +495,8 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
// ------------------- 单点注销 -------------------
/**
* 为指定账号 id 注册单点注销回调信息模式三
* 为指定账号 id 注册应用接入信息模式三
*
* @param loginId 账号id
* @param client 指定客户端标识可为null
* @param sloCallbackUrl 单点注销时的回调URL
@ -539,7 +522,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
for (;;) {
if(scmList.size() > maxRegClient) {
SaSsoClientInfo removeScm = scmList.remove(0);
notifyClientLogout(loginId, null, removeScm, true);
notifyClientLogout(loginId, null, removeScm, true, true);
} else {
break;
}
@ -591,7 +574,6 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
public void ssoLogout(Object loginId, SaLogoutParameter logoutParameter) {
// 1消息推送单点注销
// TODO 需要把对应的 SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_ 记录也删掉
pushToAllClientByLogoutCall(loginId, logoutParameter);
// 2SaSession 挂载的 Client 端注销会话
@ -601,7 +583,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
}
List<SaSsoClientInfo> scmList = session.get(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, ArrayList::new);
scmList.forEach(scm -> {
notifyClientLogout(loginId, logoutParameter.getDeviceId(), scm, false);
notifyClientLogout(loginId, logoutParameter.getDeviceId(), scm, false, false);
});
// 3Server 端本身注销
@ -614,17 +596,22 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
* @param deviceId 指定设备 id
* @param scm 客户端信息对象
* @param autoLogout 是否为超过 maxRegClient 的自动注销
* @param isPushWork 如果该 client 没有注册注销回调地址是否使用 push 消息的方式进行注销回调通知
*/
public void notifyClientLogout(Object loginId, String deviceId, SaSsoClientInfo scm, boolean autoLogout) {
public void notifyClientLogout(Object loginId, String deviceId, SaSsoClientInfo scm, boolean autoLogout, boolean isPushWork) {
// 如果给个null值不进行任何操作
if(scm == null || scm.mode != SaSsoConsts.SSO_MODE_3) {
return;
}
// 如果此 Client 并没有注册 单点登录 回调地址则立即返回
// 如果此 Client 并没有注册 单点注销 回调地址
String sloCallUrl = scm.getSloCallbackUrl();
if(SaFoxUtil.isEmpty(sloCallUrl)) {
// TODO 代码有效性待验证
if(isPushWork && SaFoxUtil.isNotEmpty(scm.getClient())) {
pushToClientByLogoutCall(getClient(scm.getClient()), loginId, getStpLogic().createSaLogoutParameter());
}
return;
}
@ -646,18 +633,6 @@ public class SaSsoServerTemplate 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);
}
/**
* 向指定 Client 推送消息
* @param clientModel /
@ -666,7 +641,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
*/
public String pushMessage(SaSsoClientModel clientModel, SaSsoMessage message) {
message.checkType();
String noticeUrl = clientModel.splicingNoticeUrl();
String noticeUrl = clientModel.splicingPushUrl();
String paramsStr = getSignTemplate(clientModel.getClient()).addSignParamsAndJoin(message);
String finalUrl = SaFoxUtil.joinParam(noticeUrl, paramsStr);
return strategy.sendHttp.apply(finalUrl);
@ -714,8 +689,8 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
* @param message /
*/
public void pushToAllClient(SaSsoMessage message) {
List<SaSsoClientModel> mode3Clients = getNeedPushClients();
for (SaSsoClientModel client : mode3Clients) {
List<SaSsoClientModel> needPushClients = getNeedPushClients();
for (SaSsoClientModel client : needPushClients) {
pushMessage(client, message);
}
}
@ -730,15 +705,25 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
List<SaSsoClientModel> npClients = getNeedPushClients();
for (SaSsoClientModel client : npClients) {
if(client.getIsSlo()) {
SaSsoMessage message = new SaSsoMessage();
message.setType(SaSsoConsts.MESSAGE_LOGOUT_CALL);
message.set(paramName.loginId, loginId);
message.set(paramName.deviceId, logoutParameter.getDeviceId());
pushMessage(client, message);
pushToClientByLogoutCall(client, loginId, logoutParameter);
}
}
}
/**
* 向指定 Client 推送消息单点注销回调
*
* @param loginId /
* @param logoutParameter 注销参数
*/
public void pushToClientByLogoutCall(SaSsoClientModel client, Object loginId, SaLogoutParameter logoutParameter) {
SaSsoMessage message = new SaSsoMessage();
message.setType(SaSsoConsts.MESSAGE_LOGOUT_CALL);
message.set(paramName.loginId, loginId);
message.set(paramName.deviceId, logoutParameter.getDeviceId());
pushMessage(client, message);
}
// ------------------- Bean 获取 -------------------
@ -776,25 +761,16 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
// ------------------- 返回相应key -------------------
/**
* 拼接keyTicket 账号Id
* 拼接keyTicketModel
* @param ticket ticket值
* @return key
*/
public String splicingTicketSaveKey(String ticket) {
public String splicingTicketModelSaveKey(String ticket) {
return getStpLogic().getConfigOrGlobal().getTokenName() + ":ticket:" + ticket;
}
// /**
// * 拼接keyTicket 所属的 client
// * @param ticket ticket值
// * @return key
// */
// public String splicingTicketToClientSaveKey(String ticket) {
// return getStpLogic().getConfigOrGlobal().getTokenName() + ":ticket-client:" + ticket;
// }
/**
* 拼接key账号Id 反查 Ticket
* 拼接keyTicket 索引
*
* @param client 应用标识
* @param id 账号id
@ -804,7 +780,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
if(SaFoxUtil.isEmpty(client) || SaSsoConsts.CLIENT_WILDCARD.equals(client)) {
client = SaSsoConsts.CLIENT_ANON;
}
return getStpLogic().getConfigOrGlobal().getTokenName() + ":id-ticket:" + client + ":" + id;
return getStpLogic().getConfigOrGlobal().getTokenName() + ":ticket-index:" + client + ":" + id;
}
}

View File

@ -0,0 +1,300 @@
/*
* 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.template;
import cn.dev33.satoken.sso.config.SaSsoClientModel;
import cn.dev33.satoken.sso.message.SaSsoMessage;
import cn.dev33.satoken.sso.model.TicketModel;
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
import cn.dev33.satoken.stp.parameter.SaLogoutParameter;
import cn.dev33.satoken.util.SaResult;
import java.util.List;
/**
* SSO 工具类 Server端
*
* @author click33
* @since 1.43.0
*/
public class SaSsoServerUtil extends SaSsoTemplate {
private SaSsoServerUtil() {
}
/**
* 返回底层使用的 SaSsoServerTemplate 对象
* @return /
*/
public static SaSsoServerTemplate getSsoTemplate() {
return SaSsoServerProcessor.instance.ssoServerTemplate;
}
// ---------------------- Ticket 操作 ----------------------
// 增删改
/**
* 删除 Ticket
* @param ticket Ticket码
*/
public static void deleteTicket(String ticket) {
SaSsoServerProcessor.instance.ssoServerTemplate.deleteTicket(ticket);
}
/**
* 根据参数创建一个 ticket 并保存
*
* @param client 客户端标识
* @param loginId 账号 id
* @param tokenValue 会话 Token
* @return Ticket码
*/
public static String createTicketAndSave(String client, Object loginId, String tokenValue) {
return SaSsoServerProcessor.instance.ssoServerTemplate.createTicketAndSave(client, loginId, tokenValue);
}
//
/**
* 查询 ticket 如果 ticket 无效则返回 null
*
* @param ticket Ticket码
* @return 账号id
*/
public static TicketModel getTicket(String ticket) {
return SaSsoServerProcessor.instance.ssoServerTemplate.getTicket(ticket);
}
/**
* 查询 ticket 指向的 loginId如果 ticket 码无效则返回 null
* @param ticket Ticket码
* @return 账号id
*/
public static Object getLoginId(String ticket) {
return SaSsoServerProcessor.instance.ssoServerTemplate.getLoginId(ticket);
}
/**
* 查询 ticket 指向的 loginId并转换为指定类型
* @param <T> 要转换的类型
* @param ticket Ticket码
* @param cs 要转换的类型
* @return 账号id
*/
public static <T> T getLoginId(String ticket, Class<T> cs) {
return SaSsoServerProcessor.instance.ssoServerTemplate.getLoginId(ticket, cs);
}
// 校验
/**
* 校验 Ticket无效 ticket 会抛出异常
*
* @param ticket Ticket码
* @return /
*/
public static TicketModel checkTicket(String ticket) {
return SaSsoServerProcessor.instance.ssoServerTemplate.checkTicket(ticket);
}
/**
* 校验 Ticket 无效 ticket 会抛出异常如果此ticket是有效的则立即删除
* @param ticket Ticket码
* @return 账号id
*/
public static TicketModel checkTicketParamAndDelete(String ticket) {
return SaSsoServerProcessor.instance.ssoServerTemplate.checkTicketParamAndDelete(ticket);
}
/**
* 校验 Ticket无效 ticket 会抛出异常如果此ticket是有效的则立即删除
*
* @param ticket Ticket码
* @param client client 标识
* @return /
*/
public static TicketModel checkTicketParamAndDelete(String ticket, String client) {
return SaSsoServerProcessor.instance.ssoServerTemplate.checkTicketParamAndDelete(ticket, client);
}
// ticket 索引
/**
* 查询 指定 clientloginId 其所属的 ticket
*
* @param client 应用
* @param loginId 账号id
* @return Ticket值
*/
public static String getTicketValue(String client, Object loginId) {
return SaSsoServerProcessor.instance.ssoServerTemplate.getTicketValue(client, loginId);
}
// ---------------------- Client 信息获取 ----------------------
/**
* 获取所有 Client
*
* @return /
*/
public static List<SaSsoClientModel> getClients() {
return SaSsoServerProcessor.instance.ssoServerTemplate.getClients();
}
/**
* 获取应用信息无效 client 返回 null
*
* @param client /
* @return /
*/
public static SaSsoClientModel getClient(String client) {
return SaSsoServerProcessor.instance.ssoServerTemplate.getClient(client);
}
/**
* 获取应用信息无效 client 则抛出异常
*
* @param client /
* @return /
*/
public static SaSsoClientModel getClientNotNull(String client) {
return SaSsoServerProcessor.instance.ssoServerTemplate.getClientNotNull(client);
}
/**
* 获取匿名 client 信息
*
* @return /
*/
public static SaSsoClientModel getAnonClient() {
return SaSsoServerProcessor.instance.ssoServerTemplate.getAnonClient();
}
/**
* 获取所有需要接收消息推送的 Client
*
* @return /
*/
public static List<SaSsoClientModel> getNeedPushClients() {
return SaSsoServerProcessor.instance.ssoServerTemplate.getNeedPushClients();
}
// ------------------- 重定向 URL 构建与校验 -------------------
/**
* 构建 URLsso-server 端向 sso-client 下放 ticket 的地址
*
* @param client 客户端标识
* @param redirect sso-client 端的重定向地址
* @param loginId 账号 id
* @param tokenValue 会话 token
* @return /
*/
public static String buildRedirectUrl(String client, String redirect, Object loginId, String tokenValue) {
return SaSsoServerProcessor.instance.ssoServerTemplate.buildRedirectUrl(client, redirect, loginId, tokenValue);
}
/**
* 校验重定向 url 合法性
*
* @param client 应用标识
* @param url 下放ticket的url地址
*/
public static void checkRedirectUrl(String client, String url) {
SaSsoServerProcessor.instance.ssoServerTemplate.checkRedirectUrl(client, url);
}
// ------------------- 单点注销 -------------------
/**
* 指定账号单点注销
*
* @param loginId 指定账号
*/
public static void ssoLogout(Object loginId) {
SaSsoServerProcessor.instance.ssoServerTemplate.ssoLogout(loginId);
}
/**
* 指定账号单点注销
*
* @param loginId 指定账号
* @param logoutParameter 注销参数
*/
public static void ssoLogout(Object loginId, SaLogoutParameter logoutParameter) {
SaSsoServerProcessor.instance.ssoServerTemplate.ssoLogout(loginId, logoutParameter);
}
// ------------------- 消息推送 -------------------
/**
* 向指定 Client 推送消息
* @param clientModel /
* @param message /
* @return /
*/
public static String pushMessage(SaSsoClientModel clientModel, SaSsoMessage message) {
return SaSsoServerProcessor.instance.ssoServerTemplate.pushMessage(clientModel, message);
}
/**
* 向指定 client 推送消息并将返回值转为 SaResult
*
* @param clientModel /
* @param message /
* @return /
*/
public static SaResult pushMessageAsSaResult(SaSsoClientModel clientModel, SaSsoMessage message) {
return SaSsoServerProcessor.instance.ssoServerTemplate.pushMessageAsSaResult(clientModel, message);
}
/**
* 向指定 Client 推送消息
* @param client /
* @param message /
* @return /
*/
public static String pushMessage(String client, SaSsoMessage message) {
return SaSsoServerProcessor.instance.ssoServerTemplate.pushMessage(client, message);
}
/**
* 向指定 client 推送消息并将返回值转为 SaResult
*
* @param client /
* @param message /
* @return /
*/
public static SaResult pushMessageAsSaResult(String client, SaSsoMessage message) {
return SaSsoServerProcessor.instance.ssoServerTemplate.pushMessageAsSaResult(client, message);
}
/**
* 向所有 Client 推送消息
*
* @param message /
*/
public static void pushToAllClient(SaSsoMessage message) {
SaSsoServerProcessor.instance.ssoServerTemplate.pushToAllClient(message);
}
}

View File

@ -15,19 +15,15 @@
*/
package cn.dev33.satoken.sso.template;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.sso.message.SaSsoMessage;
import cn.dev33.satoken.sso.message.SaSsoMessageHolder;
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 模板方法类 公共端
* SSO 模板方法类 公共端
*
* @author click33
* @since 1.30.0
@ -74,18 +70,11 @@ public class SaSsoTemplate {
// ----------- 消息处理
/**
* SSO 消息处理器 - 持有器
*/
public SaSsoMessageHolder messageHolder = new SaSsoMessageHolder();
// /**
// * 发送 Http 请求
// *
// * @param url /
// * @return /
// */
// public String request(String url) {
// return SaManager.getSaHttpTemplate().get(url);
// }
/**
* 处理指定消息
*
@ -95,5 +84,4 @@ public class SaSsoTemplate {
return messageHolder.handleMessage(this, message);
}
}

View File

@ -23,10 +23,13 @@ import java.util.Map;
/**
* Sa-Token-SSO 单点登录模块 工具类
*
* <h2> 请更换为 SaSsoServerUtil SaSsoClientUtil <h2/>
*
* @author click33
* @since 1.30.0
*/
@Deprecated
public class SaSsoUtil {
// ---------------------- Ticket 操作 ----------------------
@ -40,7 +43,7 @@ public class SaSsoUtil {
* @return Ticket码
*/
public static String createTicket(String client, Object loginId, String deviceId) {
return SaSsoServerProcessor.instance.ssoServerTemplate.createTicket(client, loginId, deviceId);
return SaSsoServerProcessor.instance.ssoServerTemplate.createTicketAndSave(client, loginId, deviceId);
}
/**

View File

@ -58,9 +58,6 @@ public class SaSsoConsts {
/** SSO 模式3 */
public static final int SSO_MODE_3 = 3;
// /** 消息类型:单点注销 */
// public static final String MESSAGE_LOGOUT = "logout";
/** 消息类型:校验 ticket */
public static final String MESSAGE_CHECK_TICKET = "checkTicket";