mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-08-20 00:44:30 +08:00
feat: sa-token-sso 模块新增消息推送机制
This commit is contained in:
parent
b53eac9269
commit
95cc77a8bc
@ -57,12 +57,12 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Http请求工具(在模式三的单点注销功能下用到,如不需要可以注释掉) -->
|
||||
|
||||
<!-- Sa-Token 插件:整合 Forest 请求工具 -->
|
||||
<dependency>
|
||||
<groupId>com.dtflys.forest</groupId>
|
||||
<artifactId>forest-spring-boot-starter</artifactId>
|
||||
<version>1.5.26</version>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-forest</artifactId>
|
||||
<version>${sa-token.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
@ -6,7 +6,6 @@ import cn.dev33.satoken.sso.config.SaSsoServerConfig;
|
||||
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.dtflys.forest.Forest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@ -50,19 +49,7 @@ public class SsoServerController {
|
||||
}
|
||||
return SaResult.error("登录失败!");
|
||||
};
|
||||
|
||||
// 配置 Http 请求处理器 (在模式三的单点注销功能下用到,如不需要可以注释掉)
|
||||
ssoServer.sendHttp = url -> {
|
||||
try {
|
||||
System.out.println("------ 发起请求:" + url);
|
||||
String resStr = Forest.get(url).executeAsString();
|
||||
System.out.println("------ 请求结果:" + resStr);
|
||||
return resStr;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// 示例:获取数据接口(用于在模式三下,为 client 端开放拉取数据的接口)
|
||||
|
@ -35,8 +35,9 @@ sa-token:
|
||||
# 应用 sso-client3,采用模式三对接 (跨域、跨Redis)
|
||||
sso-client3:
|
||||
client: sso-client3
|
||||
secret-key: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
allow-url: "*"
|
||||
secret-key: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
push-url: http://sa-sso-client1.com:9003/sso/pushC
|
||||
|
||||
|
||||
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
|
||||
|
@ -5,7 +5,6 @@ import cn.dev33.satoken.sso.config.SaSsoClientConfig;
|
||||
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.dtflys.forest.Forest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -43,13 +42,7 @@ public class SsoClientController {
|
||||
// 配置SSO相关参数
|
||||
@Autowired
|
||||
private void configSso(SaSsoClientConfig ssoClient) {
|
||||
// 配置Http请求处理器
|
||||
ssoClient.sendHttp = url -> {
|
||||
System.out.println("------ 发起请求:" + url);
|
||||
String resStr = Forest.get(url).executeAsString();
|
||||
System.out.println("------ 请求结果:" + resStr);
|
||||
return resStr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// 全局异常拦截
|
||||
|
@ -53,15 +53,16 @@
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Http请求工具 -->
|
||||
|
||||
<!-- Sa-Token 插件:整合 Forest 请求工具 -->
|
||||
<dependency>
|
||||
<groupId>com.dtflys.forest</groupId>
|
||||
<artifactId>forest-spring-boot-starter</artifactId>
|
||||
<version>1.5.26</version>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-forest</artifactId>
|
||||
<version>${sa-token.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
@ -5,7 +5,6 @@ import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||
import cn.dev33.satoken.sso.template.SaSsoUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.dtflys.forest.Forest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -45,13 +44,7 @@ public class SsoClientController {
|
||||
// 配置SSO相关参数
|
||||
@Autowired
|
||||
private void configSso(SaSsoClientConfig ssoClient) {
|
||||
// 配置Http请求处理器
|
||||
ssoClient.sendHttp = url -> {
|
||||
System.out.println("------ 发起请求:" + url);
|
||||
String resStr = Forest.get(url).executeAsString();
|
||||
System.out.println("------ 请求结果:" + resStr);
|
||||
return resStr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// 查询我的账号信息
|
||||
|
@ -21,7 +21,7 @@ import com.dtflys.forest.Forest;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Http 转换器, Forest 版实现
|
||||
* Http 请求处理器, Forest 版实现
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
|
@ -17,6 +17,7 @@ package cn.dev33.satoken.plugin;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.http.SaHttpTemplateForForest;
|
||||
import com.dtflys.forest.config.ForestConfiguration;
|
||||
|
||||
/**
|
||||
* SaToken 插件安装:Http 请求处理器 - Forest 版
|
||||
@ -28,6 +29,10 @@ public class SaTokenPluginForForest implements SaTokenPlugin {
|
||||
|
||||
@Override
|
||||
public void install() {
|
||||
// 关闭 Forest 默认日志打印
|
||||
ForestConfiguration.getDefaultConfiguration().setLogEnabled(false);
|
||||
|
||||
// 设置 Forest 作为 Http 请求处理器
|
||||
SaManager.setSaHttpTemplate(new SaHttpTemplateForForest());
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,6 @@
|
||||
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.function.SendHttpFunction;
|
||||
import cn.dev33.satoken.sso.function.TicketResultHandleFunction;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
@ -40,12 +37,12 @@ public class SaSsoClientConfig implements Serializable {
|
||||
public String mode = "";
|
||||
|
||||
/**
|
||||
* 当前 Client 名称标识,用于和 ticket 码的互相锁定
|
||||
* 当前 Client 标识
|
||||
*/
|
||||
public String client;
|
||||
|
||||
/**
|
||||
* 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、getDataUrl、sloUrl 属性前面,用以简化各种 url 配置
|
||||
* 配置 Server 端主机总地址
|
||||
*/
|
||||
public String serverUrl;
|
||||
|
||||
@ -54,11 +51,6 @@ public class SaSsoClientConfig implements Serializable {
|
||||
*/
|
||||
public String authUrl = "/sso/auth";
|
||||
|
||||
/**
|
||||
* 单独配置 Server 端的 ticket 校验地址
|
||||
*/
|
||||
public String checkTicketUrl = "/sso/checkTicket";
|
||||
|
||||
/**
|
||||
* 单独配置 Server 端查询数据 getData 地址
|
||||
*/
|
||||
@ -69,6 +61,11 @@ public class SaSsoClientConfig implements Serializable {
|
||||
*/
|
||||
public String sloUrl = "/sso/signout";
|
||||
|
||||
/**
|
||||
* 单独配置 Server 端推送消息地址
|
||||
*/
|
||||
public String pushUrl = "/sso/pushS";
|
||||
|
||||
/**
|
||||
* 配置当前 Client 端的登录地址(为空时自动获取)
|
||||
*/
|
||||
@ -80,12 +77,17 @@ public class SaSsoClientConfig implements Serializable {
|
||||
public String currSsoLogoutCall;
|
||||
|
||||
/**
|
||||
* 是否打开单点注销功能
|
||||
* 是否打开单点注销功能 (为 true 时,接收单点注销回调消息推送)
|
||||
*/
|
||||
public Boolean isSlo = true;
|
||||
|
||||
/**
|
||||
* 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、拉取数据getData)
|
||||
* 是否注册单点登录注销回调 (为 true 时,登录时附带单点登录回调地址,并且开放 /sso/logoutCall 地址)
|
||||
*/
|
||||
public Boolean regLogoutCall = false;
|
||||
|
||||
/**
|
||||
* 是否打开模式三(此值为 true 时将使用 http 请求校验 ticket 值)
|
||||
*/
|
||||
public Boolean isHttp = false;
|
||||
|
||||
@ -100,6 +102,47 @@ public class SaSsoClientConfig implements Serializable {
|
||||
public Boolean isCheckSign = true;
|
||||
|
||||
|
||||
// 额外添加的一些函数
|
||||
|
||||
/**
|
||||
* @return 获取拼接url:Server 端单点登录授权地址
|
||||
*/
|
||||
public String splicingAuthUrl() {
|
||||
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getAuthUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取拼接url:Server 端查询数据 getData 地址
|
||||
*/
|
||||
public String splicingGetDataUrl() {
|
||||
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getGetDataUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取拼接url:Server 端单点注销地址
|
||||
*/
|
||||
public String splicingSloUrl() {
|
||||
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getSloUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取拼接url:单独配置 Server 端推送消息地址
|
||||
*/
|
||||
public String splicingPushUrl() {
|
||||
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getPushUrl());
|
||||
}
|
||||
|
||||
|
||||
// -------------------- 所有回调函数 --------------------
|
||||
|
||||
/**
|
||||
* SSO-Client端:自定义校验 ticket 返回值的处理逻辑 (每次从认证中心获取校验 ticket 的结果后调用)
|
||||
* <p> 参数:loginId, back
|
||||
* <p> 返回值:返回给前端的值
|
||||
*/
|
||||
public TicketResultHandleFunction ticketResultHandle = null;
|
||||
|
||||
|
||||
// get set
|
||||
|
||||
/**
|
||||
@ -183,22 +226,6 @@ public class SaSsoClientConfig implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 配置的 Server 端的 ticket 校验地址
|
||||
*/
|
||||
public String getCheckTicketUrl() {
|
||||
return checkTicketUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param checkTicketUrl 配置 Server 端的 ticket 校验地址
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoClientConfig setCheckTicketUrl(String checkTicketUrl) {
|
||||
this.checkTicketUrl = checkTicketUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Server 端查询数据 getData 地址
|
||||
*/
|
||||
@ -231,6 +258,26 @@ public class SaSsoClientConfig implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 单独配置 Server 端推送消息地址
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public String getPushUrl() {
|
||||
return this.pushUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 单独配置 Server 端推送消息地址
|
||||
*
|
||||
* @param pushUrl /
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoClientConfig setPushUrl(String pushUrl) {
|
||||
this.pushUrl = pushUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 配置当前 Client 端的登录地址(为空时自动获取)
|
||||
*/
|
||||
@ -318,6 +365,26 @@ public class SaSsoClientConfig implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 是否注册单点登录注销回调 (为 true 时,登录时附带单点登录回调地址,并且开放 /sso/logoutCall 地址)
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public Boolean getRegLogoutCall() {
|
||||
return this.regLogoutCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 是否注册单点登录注销回调 (为 true 时,登录时附带单点登录回调地址,并且开放 /sso/logoutCall 地址)
|
||||
*
|
||||
* @param regLogoutCall /
|
||||
* @return /
|
||||
*/
|
||||
public SaSsoClientConfig setRegLogoutCall(Boolean regLogoutCall) {
|
||||
this.regLogoutCall = regLogoutCall;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaSsoClientConfig ["
|
||||
@ -325,63 +392,16 @@ public class SaSsoClientConfig implements Serializable {
|
||||
+ ", client=" + client
|
||||
+ ", serverUrl=" + serverUrl
|
||||
+ ", authUrl=" + authUrl
|
||||
+ ", checkTicketUrl=" + checkTicketUrl
|
||||
+ ", getDataUrl=" + getDataUrl
|
||||
+ ", sloUrl=" + sloUrl
|
||||
+ ", currSsoLogin=" + currSsoLogin
|
||||
+ ", currSsoLogoutCall=" + currSsoLogoutCall
|
||||
+ ", isSlo=" + isSlo
|
||||
+ ", isHttp=" + isHttp
|
||||
+ ", isSlo=" + isSlo
|
||||
+ ", regLogoutCall=" + regLogoutCall
|
||||
+ ", secretKey=" + secretKey
|
||||
+ ", isCheckSign=" + isCheckSign
|
||||
+ "]";
|
||||
}
|
||||
|
||||
// 额外添加的一些函数
|
||||
|
||||
/**
|
||||
* @return 获取拼接url:Server 端单点登录授权地址
|
||||
*/
|
||||
public String splicingAuthUrl() {
|
||||
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getAuthUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取拼接url:Server 端的 ticket 校验地址
|
||||
*/
|
||||
public String splicingCheckTicketUrl() {
|
||||
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getCheckTicketUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取拼接url:Server 端查询数据 getData 地址
|
||||
*/
|
||||
public String splicingGetDataUrl() {
|
||||
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getGetDataUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取拼接url:Server 端单点注销地址
|
||||
*/
|
||||
public String splicingSloUrl() {
|
||||
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getSloUrl());
|
||||
}
|
||||
|
||||
|
||||
// -------------------- 所有回调函数 --------------------
|
||||
|
||||
/**
|
||||
* SSO-Client端:自定义校验 ticket 返回值的处理逻辑 (每次从认证中心获取校验 ticket 的结果后调用)
|
||||
* <p> 参数:loginId, back
|
||||
* <p> 返回值:返回给前端的值
|
||||
*/
|
||||
public TicketResultHandleFunction ticketResultHandle = null;
|
||||
|
||||
/**
|
||||
* SSO-Client端:发送Http请求的处理函数
|
||||
*/
|
||||
public SendHttpFunction sendHttp = url -> {
|
||||
throw new SaSsoException("请配置 Http 请求处理器").setCode(SaSsoErrorCode.CODE_30010);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -42,6 +42,11 @@ public class SaSsoClientModel implements Serializable {
|
||||
*/
|
||||
public String allowUrl = "*";
|
||||
|
||||
/**
|
||||
* 是否打开模式三(此值为 true 时使用 http 调用方式进行消息通知)
|
||||
*/
|
||||
public Boolean isHttp = false;
|
||||
|
||||
/**
|
||||
* 是否打开单点注销功能
|
||||
*/
|
||||
@ -52,7 +57,18 @@ public class SaSsoClientModel implements Serializable {
|
||||
*/
|
||||
public String secretKey;
|
||||
|
||||
// 额外方法
|
||||
/**
|
||||
* 此 Client 端主机总地址
|
||||
*/
|
||||
public String serverUrl;
|
||||
|
||||
/**
|
||||
* 此 Client 端推送消息的地址
|
||||
*/
|
||||
public String pushUrl = "/sso/pushC";
|
||||
|
||||
|
||||
// 额外添加的一些函数
|
||||
|
||||
/**
|
||||
* 以数组形式写入允许的授权回调地址
|
||||
@ -64,6 +80,25 @@ public class SaSsoClientModel implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取拼接 url:此 Client 端推送消息的地址
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public String splicingNoticeUrl() {
|
||||
return SaFoxUtil.spliceTwoUrl(getServerUrl(), getPushUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否配置了有效地推送地址
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public boolean isValidNoticeUrl() {
|
||||
return SaFoxUtil.isUrl(splicingNoticeUrl());
|
||||
}
|
||||
|
||||
|
||||
// get set
|
||||
|
||||
/**
|
||||
@ -102,6 +137,22 @@ public class SaSsoClientModel implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isHttp 是否打开模式三
|
||||
*/
|
||||
public Boolean getIsHttp() {
|
||||
return isHttp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isHttp 是否打开模式三
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoClientModel setIsHttp(Boolean isHttp) {
|
||||
this.isHttp = isHttp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否打开单点注销功能
|
||||
*/
|
||||
@ -138,13 +189,56 @@ public class SaSsoClientModel implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 此 Client 端主机总地址
|
||||
*
|
||||
* @return serverUrl 此 Client 端主机总地址
|
||||
*/
|
||||
public String getServerUrl() {
|
||||
return this.serverUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 此 Client 端主机总地址
|
||||
*
|
||||
* @param serverUrl 此 Client 端主机总地址
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoClientModel setServerUrl(String serverUrl) {
|
||||
this.serverUrl = serverUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 此 Client 端推送消息的地址
|
||||
*
|
||||
* @return noticeUrl 此 Client 端推送消息的地址
|
||||
*/
|
||||
public String getPushUrl() {
|
||||
return this.pushUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 此 Client 端推送消息的地址
|
||||
*
|
||||
* @param pushUrl 此 Client 端推送消息的地址
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoClientModel setPushUrl(String pushUrl) {
|
||||
this.pushUrl = pushUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaSsoClientModel ["
|
||||
+ "client=" + client
|
||||
+ ", allowUrl=" + allowUrl
|
||||
+ ", isSlo=" + isSlo
|
||||
+ ", isHttp=" + isHttp
|
||||
+ ", secretKey=" + secretKey
|
||||
+ ", serverUrl=" + serverUrl
|
||||
+ ", pushUrl=" + pushUrl
|
||||
+ "]";
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,9 @@
|
||||
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.function.CheckTicketAppendDataFunction;
|
||||
import cn.dev33.satoken.sso.function.DoLoginHandleFunction;
|
||||
import cn.dev33.satoken.sso.function.NotLoginViewFunction;
|
||||
import cn.dev33.satoken.sso.function.SendHttpFunction;
|
||||
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
@ -54,11 +51,6 @@ public class SaSsoServerConfig implements Serializable {
|
||||
*/
|
||||
public long ticketTimeout = 60 * 5;
|
||||
|
||||
/**
|
||||
* 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
|
||||
*/
|
||||
public String allowUrl = "*";
|
||||
|
||||
/**
|
||||
* 主页路由:在 /sso/auth 登录后不指定 redirect 参数的情况下默认跳转的路由
|
||||
*/
|
||||
@ -69,41 +61,43 @@ public class SaSsoServerConfig implements Serializable {
|
||||
*/
|
||||
public Boolean isSlo = true;
|
||||
|
||||
/**
|
||||
* 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo)
|
||||
*/
|
||||
public Boolean isHttp = false;
|
||||
|
||||
/**
|
||||
* 是否在每次下发 ticket 时,自动续期 token 的有效期(根据全局 timeout 值)
|
||||
*/
|
||||
public Boolean autoRenewTimeout = false;
|
||||
|
||||
/**
|
||||
* 在 Access-Session 上记录 Client 信息的最高数量(-1=无限),超过此值将进行自动清退处理,先进先出
|
||||
* 在 Account-Session 上记录 Client 信息的最高数量(-1=无限),超过此值将进行自动清退处理,先进先出
|
||||
*/
|
||||
public int maxRegClient = 32;
|
||||
|
||||
/**
|
||||
* 是否允许匿名 Client 接入
|
||||
*/
|
||||
public Boolean allowAnonClient = true;
|
||||
|
||||
/**
|
||||
* 是否校验参数签名(方便本地调试用的一个配置项,生产环境请务必为true)
|
||||
*/
|
||||
public Boolean isCheckSign = true;
|
||||
|
||||
/**
|
||||
* API 调用签名秘钥
|
||||
*/
|
||||
public String secretKey;
|
||||
|
||||
/**
|
||||
* Client 信息配置列表
|
||||
*/
|
||||
public Map<String, SaSsoClientModel> clients = new LinkedHashMap<>();
|
||||
|
||||
// 匿名 Client 相关配置
|
||||
|
||||
/**
|
||||
* 是否允许匿名 Client 接入
|
||||
*/
|
||||
public Boolean allowAnonClient = true;
|
||||
|
||||
/**
|
||||
* 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket) (匿名 client 使用)
|
||||
*/
|
||||
public String allowUrl = "*";
|
||||
|
||||
/**
|
||||
* API 调用签名秘钥 (全局默认 + 匿名 client 使用)
|
||||
*/
|
||||
public String secretKey;
|
||||
|
||||
|
||||
// 额外方法
|
||||
|
||||
@ -128,6 +122,31 @@ public class SaSsoServerConfig implements Serializable {
|
||||
}
|
||||
|
||||
|
||||
// -------------------- 所有回调函数 --------------------
|
||||
|
||||
|
||||
/**
|
||||
* SSO-Server端:未登录时返回的View
|
||||
*/
|
||||
public NotLoginViewFunction notLoginView = () -> {
|
||||
return "当前会话在SSO-Server认证中心尚未登录(当前未配置登录视图)";
|
||||
};
|
||||
|
||||
/**
|
||||
* SSO-Server端:登录函数
|
||||
*/
|
||||
public DoLoginHandleFunction doLoginHandle = (name, pwd) -> {
|
||||
return SaResult.error();
|
||||
};
|
||||
|
||||
/**
|
||||
* SSO-Server端:在校验 ticket 后,给 sso-client 端追加返回信息的函数
|
||||
*/
|
||||
public CheckTicketAppendDataFunction checkTicketAppendData = (loginId, result) -> {
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
// get set
|
||||
|
||||
/**
|
||||
@ -165,14 +184,14 @@ public class SaSsoServerConfig implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
|
||||
* @return 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket) (匿名 client 使用)
|
||||
*/
|
||||
public String getAllowUrl() {
|
||||
return allowUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allowUrl 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
|
||||
* @param allowUrl 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket) (匿名 client 使用)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoServerConfig setAllowUrl(String allowUrl) {
|
||||
@ -217,22 +236,6 @@ public class SaSsoServerConfig implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isHttp 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo)
|
||||
*/
|
||||
public Boolean getIsHttp() {
|
||||
return isHttp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isHttp 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoServerConfig setIsHttp(Boolean isHttp) {
|
||||
this.isHttp = isHttp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否在每次下发 ticket 时,自动续期 token 的有效期(根据全局 timeout 值)
|
||||
*/
|
||||
@ -250,14 +253,14 @@ public class SaSsoServerConfig implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return maxLoginClient 在 Access-Session 上记录 Client 信息的最高数量(-1=无限),超过此值将进行自动清退处理,先进先出
|
||||
* @return maxLoginClient 在 Account-Session 上记录 Client 信息的最高数量(-1=无限),超过此值将进行自动清退处理,先进先出
|
||||
*/
|
||||
public int getMaxRegClient() {
|
||||
return maxRegClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxRegClient 在 Access-Session 上记录 Client 信息的最高数量(-1=无限),超过此值将进行自动清退处理,先进先出
|
||||
* @param maxRegClient 在 Account-Session 上记录 Client 信息的最高数量(-1=无限),超过此值将进行自动清退处理,先进先出
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoServerConfig setMaxRegClient(int maxRegClient) {
|
||||
@ -304,7 +307,7 @@ public class SaSsoServerConfig implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 API 调用签名秘钥
|
||||
* 获取 API 调用签名秘钥 (全局默认 + 匿名 client 使用)
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
@ -313,7 +316,7 @@ public class SaSsoServerConfig implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 API 调用签名秘钥
|
||||
* 设置 API 调用签名秘钥 (全局默认 + 匿名 client 使用)
|
||||
*
|
||||
* @param secretKey /
|
||||
* @return 对象自身
|
||||
@ -351,7 +354,6 @@ public class SaSsoServerConfig implements Serializable {
|
||||
+ ", allowUrl=" + allowUrl
|
||||
+ ", homeRoute=" + homeRoute
|
||||
+ ", isSlo=" + isSlo
|
||||
+ ", isHttp=" + isHttp
|
||||
+ ", autoRenewTimeout=" + autoRenewTimeout
|
||||
+ ", maxRegClient=" + maxRegClient
|
||||
+ ", isCheckSign=" + isCheckSign
|
||||
@ -362,107 +364,4 @@ public class SaSsoServerConfig implements Serializable {
|
||||
}
|
||||
|
||||
|
||||
// -------------------- 所有回调函数 --------------------
|
||||
|
||||
|
||||
/**
|
||||
* SSO-Server端:未登录时返回的View
|
||||
*/
|
||||
public NotLoginViewFunction notLoginView = () -> {
|
||||
return "当前会话在SSO-Server认证中心尚未登录(当前未配置登录视图)";
|
||||
};
|
||||
|
||||
/**
|
||||
* SSO-Server端:登录函数
|
||||
*/
|
||||
public DoLoginHandleFunction doLoginHandle = (name, pwd) -> {
|
||||
return SaResult.error();
|
||||
};
|
||||
|
||||
/**
|
||||
* SSO-Server端:在校验 ticket 后,给 sso-client 端追加返回信息的函数
|
||||
*/
|
||||
public CheckTicketAppendDataFunction checkTicketAppendData = (loginId, result) -> {
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* SSO-Server端:发送Http请求的处理函数
|
||||
*/
|
||||
public SendHttpFunction sendHttp = url -> {
|
||||
throw new SaSsoException("请配置 Http 请求处理器").setCode(SaSsoErrorCode.CODE_30010);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取 SSO-Server端:未登录时返回的View
|
||||
*
|
||||
* @return notLoginView SSO-Server端:未登录时返回的View
|
||||
*/
|
||||
public NotLoginViewFunction getNotLoginView() {
|
||||
return this.notLoginView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 SSO-Server端:未登录时返回的View
|
||||
*
|
||||
* @param notLoginView SSO-Server端:未登录时返回的View
|
||||
*/
|
||||
public void setNotLoginView(NotLoginViewFunction notLoginView) {
|
||||
this.notLoginView = notLoginView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 SSO-Server端:登录函数
|
||||
*
|
||||
* @return doLoginHandle SSO-Server端:登录函数
|
||||
*/
|
||||
public DoLoginHandleFunction getDoLoginHandle() {
|
||||
return this.doLoginHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 SSO-Server端:登录函数
|
||||
*
|
||||
* @param doLoginHandle SSO-Server端:登录函数
|
||||
*/
|
||||
public void setDoLoginHandle(DoLoginHandleFunction doLoginHandle) {
|
||||
this.doLoginHandle = doLoginHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 SSO-Server端:在校验 ticket 后,给 sso-client 端追加返回信息的函数
|
||||
*
|
||||
* @return checkTicketAppendData SSO-Server端:在校验 ticket 后,给 sso-client 端追加返回信息的函数
|
||||
*/
|
||||
public CheckTicketAppendDataFunction getCheckTicketAppendData() {
|
||||
return this.checkTicketAppendData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 SSO-Server端:在校验 ticket 后,给 sso-client 端追加返回信息的函数
|
||||
*
|
||||
* @param checkTicketAppendData SSO-Server端:在校验 ticket 后,给 sso-client 端追加返回信息的函数
|
||||
*/
|
||||
public void setCheckTicketAppendData(CheckTicketAppendDataFunction checkTicketAppendData) {
|
||||
this.checkTicketAppendData = checkTicketAppendData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 SSO-Server端:发送Http请求的处理函数
|
||||
*
|
||||
* @return sendHttp SSO-Server端:发送Http请求的处理函数
|
||||
*/
|
||||
public SendHttpFunction getSendHttp() {
|
||||
return this.sendHttp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 SSO-Server端:发送Http请求的处理函数
|
||||
*
|
||||
* @param sendHttp SSO-Server端:发送Http请求的处理函数
|
||||
*/
|
||||
public void setSendHttp(SendHttpFunction sendHttp) {
|
||||
this.sendHttp = sendHttp;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -68,4 +68,13 @@ public interface SaSsoErrorCode {
|
||||
/** 无效的 allow-url 配置 */
|
||||
int CODE_30015 = 30015;
|
||||
|
||||
/** 未能找到指定类型的消息处理器 */
|
||||
int CODE_30021 = 30021;
|
||||
|
||||
/** 消息类型不能为空 */
|
||||
int CODE_30022 = 30022;
|
||||
|
||||
/** 无效的消息推送地址 */
|
||||
int CODE_30023 = 30023;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.message;
|
||||
|
||||
|
||||
import cn.dev33.satoken.application.SaSetValueInterface;
|
||||
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
|
||||
import cn.dev33.satoken.sso.exception.SaSsoException;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Sa-Token SSO 消息 Model
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public class SaSsoMessage extends LinkedHashMap<String, Object> implements SaSetValueInterface, Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* KEY:TYPE
|
||||
*/
|
||||
public static final String MSG_TYPE = "msg_type";
|
||||
|
||||
public SaSsoMessage() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param type 消息类型
|
||||
*/
|
||||
public SaSsoMessage(String type) {
|
||||
setType(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param map 消息参数
|
||||
*/
|
||||
public SaSsoMessage(Map<String, ?> map) {
|
||||
this.putAll(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息类型
|
||||
* @return /
|
||||
*/
|
||||
public String getType() {
|
||||
return getString(MSG_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息类型
|
||||
* @param type /
|
||||
* @return /
|
||||
*/
|
||||
public SaSsoMessage setType(String type) {
|
||||
return set(MSG_TYPE, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验消息类型
|
||||
*/
|
||||
public void checkType() {
|
||||
if(SaFoxUtil.isEmpty(getString(MSG_TYPE))) {
|
||||
throw new SaSsoException("消息类型不可为空").setCode(SaSsoErrorCode.CODE_30022);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------
|
||||
|
||||
@Override
|
||||
public Object get(String key) {
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaSsoMessage set(String key, Object value) {
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaSsoMessage delete(String key) {
|
||||
super.remove(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.message;
|
||||
|
||||
|
||||
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
|
||||
import cn.dev33.satoken.sso.exception.SaSsoException;
|
||||
import cn.dev33.satoken.sso.message.handle.SaSsoMessageHandle;
|
||||
import cn.dev33.satoken.sso.template.SaSsoTemplate;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Sa-Token SSO 消息处理器持有者
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public class SaSsoMessageHolder {
|
||||
|
||||
/**
|
||||
* 所有消息处理器的集合
|
||||
*/
|
||||
public final Map<String, SaSsoMessageHandle> messageHandleMap = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 判断是否具有指定类型的消息处理器
|
||||
*
|
||||
* @param type 消息类型
|
||||
* @return /
|
||||
*/
|
||||
public boolean hasHandle(String type) {
|
||||
return messageHandleMap.containsKey(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定类型的消息处理器
|
||||
*
|
||||
* @param type 消息类型
|
||||
*/
|
||||
public SaSsoMessageHolder removeHandle(String type) {
|
||||
messageHandleMap.remove(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加指定类型的消息处理器
|
||||
*
|
||||
* @param handle /
|
||||
*/
|
||||
public SaSsoMessageHolder addHandle(SaSsoMessageHandle handle) {
|
||||
messageHandleMap.put(handle.getHandlerType(), handle);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类型的消息处理器
|
||||
*
|
||||
* @param type /
|
||||
*/
|
||||
public SaSsoMessageHandle getHandle(String type) {
|
||||
return messageHandleMap.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理指定消息
|
||||
*
|
||||
* @param ssoTemplate /
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public Object handleMessage(SaSsoTemplate ssoTemplate, SaSsoMessage message) {
|
||||
SaSsoMessageHandle handle = messageHandleMap.get(message.getType());
|
||||
if(handle == null) {
|
||||
throw new SaSsoException("未能找到消息处理器: " + message.getType()).setCode(SaSsoErrorCode.CODE_30021);
|
||||
}
|
||||
return handle.handle(ssoTemplate, message);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.message.handle;
|
||||
|
||||
|
||||
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||
import cn.dev33.satoken.sso.template.SaSsoTemplate;
|
||||
|
||||
/**
|
||||
* Sa-Token SSO 消息 处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public interface SaSsoMessageHandle {
|
||||
|
||||
/**
|
||||
* 获取所要处理的消息类型
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String getHandlerType();
|
||||
|
||||
/**
|
||||
* 执行方法
|
||||
*
|
||||
* @param ssoTemplate /
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
Object handle(SaSsoTemplate ssoTemplate, SaSsoMessage message);
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.message.handle.client;
|
||||
|
||||
|
||||
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;
|
||||
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
|
||||
import cn.dev33.satoken.sso.template.SaSsoTemplate;
|
||||
import cn.dev33.satoken.sso.util.SaSsoConsts;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
/**
|
||||
* Sa-Token SSO 消息 处理器 - sso-client 端:处理 单点注销回调 的请求
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public class SaSsoMessageLogoutCallHandle implements SaSsoMessageHandle {
|
||||
|
||||
/**
|
||||
* 获取所要处理的消息类型
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public String getHandlerType() {
|
||||
return SaSsoConsts.MESSAGE_LOGOUT_CALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行方法
|
||||
*
|
||||
* @param ssoTemplate /
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public Object handle(SaSsoTemplate ssoTemplate, SaSsoMessage message) {
|
||||
SaSsoClientTemplate ssoClientTemplate = (SaSsoClientTemplate) ssoTemplate;
|
||||
if( ! ssoClientTemplate.getClientConfig().getIsSlo()) {
|
||||
return SaResult.error("当前 sso-client 端未开启单点注销功能");
|
||||
}
|
||||
|
||||
// 获取对象
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
|
||||
ParamName paramName = ssoClientTemplate.paramName;
|
||||
|
||||
// 获取参数
|
||||
String loginId = req.getParamNotNull(paramName.loginId);
|
||||
|
||||
// 注销当前应用端会话
|
||||
stpLogic.logout(loginId);
|
||||
|
||||
// 响应
|
||||
return SaResult.ok("单点注销回调成功");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.message.handle.server;
|
||||
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.sso.SaSsoManager;
|
||||
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.name.ParamName;
|
||||
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
|
||||
import cn.dev33.satoken.sso.template.SaSsoTemplate;
|
||||
import cn.dev33.satoken.sso.util.SaSsoConsts;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
/**
|
||||
* Sa-Token SSO 消息 处理器 - sso-server 端:处理校验 ticket 的请求
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public class SaSsoMessageCheckTicketHandle implements SaSsoMessageHandle {
|
||||
|
||||
/**
|
||||
* 获取所要处理的消息类型
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public String getHandlerType() {
|
||||
return SaSsoConsts.MESSAGE_CHECK_TICKET;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行方法
|
||||
*
|
||||
* @param ssoTemplate /
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public Object handle(SaSsoTemplate ssoTemplate, SaSsoMessage message) {
|
||||
SaSsoServerTemplate ssoServerTemplate = (SaSsoServerTemplate) ssoTemplate;
|
||||
ParamName paramName = ssoServerTemplate.paramName;
|
||||
|
||||
// 1、获取参数
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
SaSsoServerConfig ssoServerConfig = ssoServerTemplate.getServerConfig();
|
||||
String client = req.getParam(paramName.client);
|
||||
String ticket = req.getParamNotNull(paramName.ticket);
|
||||
String sloCallback = req.getParam(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
|
||||
Object loginId = ssoServerTemplate.checkTicket(ticket, client);
|
||||
if(SaFoxUtil.isEmpty(loginId)) {
|
||||
return SaResult.error("无效ticket:" + ticket);
|
||||
}
|
||||
|
||||
// 5、注册此客户端的单点注销回调URL
|
||||
ssoServerTemplate.registerSloCallbackUrl(loginId, client, sloCallback);
|
||||
|
||||
// 6、给 client 端响应结果
|
||||
long remainSessionTimeout = ssoServerTemplate.getStpLogic().getSessionTimeoutByLoginId(loginId);
|
||||
SaResult result = SaResult.data(loginId).set(paramName.remainSessionTimeout, remainSessionTimeout);
|
||||
result = ssoServerConfig.checkTicketAppendData.apply(loginId, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.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;
|
||||
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
|
||||
import cn.dev33.satoken.sso.template.SaSsoTemplate;
|
||||
import cn.dev33.satoken.sso.util.SaSsoConsts;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
/**
|
||||
* Sa-Token SSO 消息 处理器 - sso-server 端:处理 单点注销 的请求
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public class SaSsoMessageSignoutHandle implements SaSsoMessageHandle {
|
||||
|
||||
/**
|
||||
* 获取所要处理的消息类型
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public String getHandlerType() {
|
||||
return SaSsoConsts.MESSAGE_SIGNOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行方法
|
||||
*
|
||||
* @param ssoTemplate /
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public Object handle(SaSsoTemplate ssoTemplate, SaSsoMessage message) {
|
||||
SaSsoServerTemplate ssoServerTemplate = (SaSsoServerTemplate) ssoTemplate;
|
||||
ParamName paramName = ssoServerTemplate.paramName;
|
||||
|
||||
if( ! ssoServerTemplate.getServerConfig().getIsSlo()) {
|
||||
return SaResult.error("当前 sso-server 端未开启单点注销功能");
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
String loginId = req.getParam(paramName.loginId);
|
||||
|
||||
// step.2 单点注销
|
||||
ssoServerTemplate.ssoLogout(loginId);
|
||||
|
||||
// 响应
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
}
|
@ -32,6 +32,9 @@ public class ApiName {
|
||||
/** SSO-Server端:校验ticket 获取账号id */
|
||||
public String ssoCheckTicket = "/sso/checkTicket";
|
||||
|
||||
/** SSO-Server端:接受推送消息 */
|
||||
public String ssoPushS = "/sso/pushS";
|
||||
|
||||
/** SSO-Server端:获取userinfo */
|
||||
public String ssoUserinfo = "/sso/userinfo";
|
||||
|
||||
@ -46,7 +49,10 @@ public class ApiName {
|
||||
|
||||
/** SSO-Client端:单点注销的回调 */
|
||||
public String ssoLogoutCall = "/sso/logoutCall";
|
||||
|
||||
|
||||
/** SSO-Client端:接受推送消息 */
|
||||
public String ssoPushC = "/sso/pushC";
|
||||
|
||||
/**
|
||||
* 批量修改path,新增固定前缀
|
||||
* @param prefix 示例值:/sso-user、/sso-admin
|
||||
@ -56,10 +62,12 @@ public class ApiName {
|
||||
this.ssoAuth = prefix + this.ssoAuth;
|
||||
this.ssoDoLogin = prefix + this.ssoDoLogin;
|
||||
this.ssoCheckTicket = prefix + this.ssoCheckTicket;
|
||||
this.ssoPushS = prefix + this.ssoPushS;
|
||||
this.ssoUserinfo = prefix + this.ssoUserinfo;
|
||||
this.ssoSignout = prefix + this.ssoSignout;
|
||||
this.ssoLogin = prefix + this.ssoLogin;
|
||||
this.ssoLogout = prefix + this.ssoLogout;
|
||||
this.ssoPushC = prefix + this.ssoPushC;
|
||||
this.ssoLogoutCall = prefix + this.ssoLogoutCall;
|
||||
return this;
|
||||
}
|
||||
@ -74,21 +82,30 @@ public class ApiName {
|
||||
this.ssoAuth = this.ssoAuth.replaceFirst(oldPrefix, prefix);
|
||||
this.ssoDoLogin = this.ssoDoLogin.replaceFirst(oldPrefix, prefix);
|
||||
this.ssoCheckTicket = this.ssoCheckTicket.replaceFirst(oldPrefix, prefix);
|
||||
this.ssoPushS = this.ssoPushS.replaceFirst(oldPrefix, prefix);
|
||||
this.ssoUserinfo = this.ssoUserinfo.replaceFirst(oldPrefix, prefix);
|
||||
this.ssoSignout = this.ssoSignout.replaceFirst(oldPrefix, prefix);
|
||||
this.ssoLogin = this.ssoLogin.replaceFirst(oldPrefix, prefix);
|
||||
this.ssoLogout = this.ssoLogout.replaceFirst(oldPrefix, prefix);
|
||||
this.ssoPushC = this.ssoPushC.replaceFirst(oldPrefix, prefix);
|
||||
this.ssoLogoutCall = this.ssoLogoutCall.replaceFirst(oldPrefix, prefix);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApiName [ssoAuth=" + ssoAuth + ", ssoDoLogin=" + ssoDoLogin + ", ssoCheckTicket=" + ssoCheckTicket
|
||||
+ ", ssoUserinfo=" + ssoUserinfo + ", ssoSignout=" + ssoSignout + ", ssoLogin=" + ssoLogin
|
||||
+ ", ssoLogout=" + ssoLogout + ", ssoLogoutCall=" + ssoLogoutCall + "]";
|
||||
return "ApiName{" +
|
||||
"ssoAuth='" + ssoAuth + '\'' +
|
||||
", ssoDoLogin='" + ssoDoLogin + '\'' +
|
||||
", ssoCheckTicket='" + ssoCheckTicket + '\'' +
|
||||
", ssoPushS='" + ssoPushS + '\'' +
|
||||
", ssoUserinfo='" + ssoUserinfo + '\'' +
|
||||
", ssoSignout='" + ssoSignout + '\'' +
|
||||
", ssoLogin='" + ssoLogin + '\'' +
|
||||
", ssoLogout='" + ssoLogout + '\'' +
|
||||
", ssoLogoutCall='" + ssoLogoutCall + '\'' +
|
||||
", ssoPushC='" + ssoPushC + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import cn.dev33.satoken.sso.SaSsoManager;
|
||||
import cn.dev33.satoken.sso.config.SaSsoClientConfig;
|
||||
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
|
||||
import cn.dev33.satoken.sso.exception.SaSsoException;
|
||||
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||
import cn.dev33.satoken.sso.model.SaCheckTicketResult;
|
||||
import cn.dev33.satoken.sso.name.ApiName;
|
||||
import cn.dev33.satoken.sso.name.ParamName;
|
||||
@ -31,6 +32,8 @@ import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SSO 请求处理器 (Client端)
|
||||
*
|
||||
@ -74,8 +77,13 @@ public class SaSsoClientProcessor {
|
||||
return ssoLogout();
|
||||
}
|
||||
|
||||
// ---------- SSO-Client端:接收消息推送
|
||||
if(req.isPath(apiName.ssoPushC)) {
|
||||
return ssoPushC();
|
||||
}
|
||||
|
||||
// ---------- SSO-Client端:单点注销的回调 [模式三]
|
||||
if(req.isPath(apiName.ssoLogoutCall) && cfg.getIsSlo() && cfg.getIsHttp()) {
|
||||
if(req.isPath(apiName.ssoLogoutCall) && cfg.getRegLogoutCall()) {
|
||||
return ssoLogoutCall();
|
||||
}
|
||||
|
||||
@ -154,6 +162,27 @@ public class SaSsoClientProcessor {
|
||||
return SaSsoConsts.NOT_HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* SSO-Client端:接收推送消息
|
||||
*
|
||||
* @return 处理结果
|
||||
*/
|
||||
public Object ssoPushC() {
|
||||
SaSsoClientConfig ssoClientConfig = ssoClientTemplate.getClientConfig();
|
||||
|
||||
// 1、校验签名
|
||||
Map<String, String> paramMap = SaHolder.getRequest().getParamMap();
|
||||
if(ssoClientConfig.getIsCheckSign()) {
|
||||
ssoClientTemplate.getSignTemplate(ssoClientConfig.getClient()).checkParamMap(paramMap);
|
||||
} else {
|
||||
SaSsoManager.printNoCheckSignWarningByRuntime();
|
||||
}
|
||||
|
||||
// 2、处理消息
|
||||
SaSsoMessage message = new SaSsoMessage(paramMap);
|
||||
return ssoClientTemplate.handleMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* SSO-Client端:单点注销 [模式二]
|
||||
* @return 处理结果
|
||||
@ -189,8 +218,8 @@ public class SaSsoClientProcessor {
|
||||
}
|
||||
|
||||
// 调用 sso-server 认证中心单点注销API
|
||||
String url = ssoClientTemplate.buildSloUrl(stpLogic.getLoginId());
|
||||
SaResult result = ssoClientTemplate.request(url);
|
||||
SaSsoMessage message = ssoClientTemplate.buildSloMessage(stpLogic.getLoginId());
|
||||
SaResult result = ssoClientTemplate.pushMessageAsSaResult(message);
|
||||
|
||||
// 校验响应状态码
|
||||
if(result.getCode() != null && SaResult.CODE_SUCCESS == result.getCode()) {
|
||||
@ -224,8 +253,7 @@ public class SaSsoClientProcessor {
|
||||
|
||||
// 校验参数签名
|
||||
if(ssoConfig.getIsCheckSign()) {
|
||||
ssoClientTemplate.getSignTemplate(ssoConfig.getClient()).
|
||||
checkRequest(req, paramName.loginId, paramName.client, paramName.autoLogout);
|
||||
ssoClientTemplate.getSignTemplate(ssoConfig.getClient()).checkRequest(req, paramName.loginId, paramName.client, paramName.autoLogout);
|
||||
} else {
|
||||
SaSsoManager.printNoCheckSignWarningByRuntime();
|
||||
}
|
||||
@ -256,7 +284,7 @@ public class SaSsoClientProcessor {
|
||||
|
||||
// 计算当前 sso-client 的单点注销回调地址
|
||||
String ssoLogoutCall = null;
|
||||
if(cfg.getIsSlo()) {
|
||||
if(cfg.getRegLogoutCall()) {
|
||||
// 如果配置了回调地址,就使用配置的值:
|
||||
if(SaFoxUtil.isNotEmpty(cfg.getCurrSsoLogoutCall())) {
|
||||
ssoLogoutCall = cfg.getCurrSsoLogoutCall();
|
||||
@ -270,11 +298,9 @@ public class SaSsoClientProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
// 构建请求URL
|
||||
String checkUrl = ssoClientTemplate.buildCheckTicketUrl(ticket, ssoLogoutCall);
|
||||
|
||||
// 发起请求
|
||||
SaResult result = ssoClientTemplate.request(checkUrl);
|
||||
SaSsoMessage message = ssoClientTemplate.buildCheckTicketMessage(ticket, ssoLogoutCall);
|
||||
SaResult result = ssoClientTemplate.pushMessageAsSaResult(message);
|
||||
|
||||
// 校验
|
||||
if(result.getCode() != null && result.getCode() == SaResult.CODE_SUCCESS) {
|
||||
|
@ -22,6 +22,7 @@ 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.message.SaSsoMessage;
|
||||
import cn.dev33.satoken.sso.name.ApiName;
|
||||
import cn.dev33.satoken.sso.name.ParamName;
|
||||
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
|
||||
@ -30,6 +31,8 @@ import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SSO 请求处理器 (Server端)
|
||||
*
|
||||
@ -63,26 +66,26 @@ public class SaSsoServerProcessor {
|
||||
|
||||
// ------------------ 路由分发 ------------------
|
||||
|
||||
// ---------- SSO-Server端:授权地址
|
||||
// sso-server:授权地址
|
||||
if(req.isPath(apiName.ssoAuth)) {
|
||||
return ssoAuth();
|
||||
}
|
||||
|
||||
// ---------- SSO-Server端:RestAPI 登录接口
|
||||
// sso-server:RestAPI 登录接口
|
||||
if(req.isPath(apiName.ssoDoLogin)) {
|
||||
return ssoDoLogin();
|
||||
}
|
||||
|
||||
// ---------- SSO-Server端:校验ticket 获取账号id
|
||||
if(req.isPath(apiName.ssoCheckTicket) && cfg.getIsHttp()) {
|
||||
return ssoCheckTicket();
|
||||
}
|
||||
|
||||
// ---------- SSO-Server端:单点注销
|
||||
// sso-server:单点注销
|
||||
if(req.isPath(apiName.ssoSignout)) {
|
||||
return ssoSignout();
|
||||
}
|
||||
|
||||
// sso-server:接收推送消息
|
||||
if(req.isPath(apiName.ssoPushS)) {
|
||||
return ssoPush();
|
||||
}
|
||||
|
||||
// 默认返回
|
||||
return SaSsoConsts.NOT_HANDLE;
|
||||
}
|
||||
@ -162,78 +165,11 @@ public class SaSsoServerProcessor {
|
||||
return cfg.doLoginHandle.apply(req.getParam(paramName.name), req.getParam(paramName.pwd));
|
||||
}
|
||||
|
||||
/**
|
||||
* SSO-Server端:校验ticket 获取账号id [模式三]
|
||||
* @return 处理结果
|
||||
*/
|
||||
public Object ssoCheckTicket() {
|
||||
ParamName paramName = ssoServerTemplate.paramName;
|
||||
|
||||
// 1、获取参数
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
SaSsoServerConfig ssoServerConfig = ssoServerTemplate.getServerConfig();
|
||||
String client = req.getParam(paramName.client);
|
||||
String ticket = req.getParamNotNull(paramName.ticket);
|
||||
String sloCallback = req.getParam(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
|
||||
Object loginId = ssoServerTemplate.checkTicket(ticket, client);
|
||||
if(SaFoxUtil.isEmpty(loginId)) {
|
||||
return SaResult.error("无效ticket:" + ticket);
|
||||
}
|
||||
|
||||
// 5、注册此客户端的单点注销回调URL
|
||||
ssoServerTemplate.registerSloCallbackUrl(loginId, client, sloCallback);
|
||||
|
||||
// 6、给 client 端响应结果
|
||||
long remainSessionTimeout = ssoServerTemplate.getStpLogic().getSessionTimeoutByLoginId(loginId);
|
||||
SaResult result = SaResult.data(loginId).set(paramName.remainSessionTimeout, remainSessionTimeout);
|
||||
result = ssoServerConfig.checkTicketAppendData.apply(loginId, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* SSO-Server端:单点注销
|
||||
* @return 处理结果
|
||||
*/
|
||||
public Object ssoSignout() {
|
||||
// 获取对象
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
SaSsoServerConfig cfg = ssoServerTemplate.getServerConfig();
|
||||
ParamName paramName = ssoServerTemplate.paramName;
|
||||
|
||||
// SSO-Server端:单点注销 [用户访问式] (不带loginId参数)
|
||||
if(cfg.getIsSlo() && ! req.hasParam(paramName.loginId)) {
|
||||
return ssoSignoutByUserVisit();
|
||||
}
|
||||
|
||||
// SSO-Server端:单点注销 [Client调用式] (带loginId参数)
|
||||
if(cfg.getIsSlo() && req.hasParam(paramName.loginId)) {
|
||||
return ssoSignoutByClientHttp();
|
||||
}
|
||||
|
||||
// 默认返回
|
||||
return SaSsoConsts.NOT_HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* SSO-Server端:单点注销 [用户访问式]
|
||||
* @return 处理结果
|
||||
*/
|
||||
public Object ssoSignoutByUserVisit() {
|
||||
// 获取对象
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
SaResponse res = SaHolder.getResponse();
|
||||
@ -245,43 +181,41 @@ public class SaSsoServerProcessor {
|
||||
}
|
||||
|
||||
// 完成
|
||||
return ssoLogoutBack(req, res);
|
||||
return SaSsoProcessorHelper.ssoLogoutBack(req, res, ssoServerTemplate.paramName);
|
||||
}
|
||||
|
||||
/**
|
||||
* SSO-Server端:单点注销 [Client调用式]
|
||||
* SSO-Server端:接收推送消息
|
||||
*
|
||||
* @return 处理结果
|
||||
*/
|
||||
public Object ssoSignoutByClientHttp() {
|
||||
public Object ssoPush() {
|
||||
ParamName paramName = ssoServerTemplate.paramName;
|
||||
SaSsoServerConfig ssoServerConfig = ssoServerTemplate.getServerConfig();
|
||||
|
||||
// 获取参数
|
||||
// 1、获取参数
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
String loginId = req.getParam(paramName.loginId);
|
||||
String client = req.getParam(paramName.client);
|
||||
|
||||
// step.1 校验签名
|
||||
if(ssoServerTemplate.getServerConfig().getIsCheckSign()) {
|
||||
ssoServerTemplate.getSignTemplate(client).checkRequest(req, paramName.client, paramName.loginId);
|
||||
// 2、校验提供的client是否为非法字符
|
||||
if(SaSsoConsts.CLIENT_WILDCARD.equals(client)) {
|
||||
return SaResult.error("无效 client 标识:" + client);
|
||||
}
|
||||
|
||||
// 3、校验签名
|
||||
Map<String, String> paramMap = req.getParamMap();
|
||||
if(ssoServerConfig.getIsCheckSign()) {
|
||||
ssoServerTemplate.getSignTemplate(client).checkParamMap(paramMap);
|
||||
} else {
|
||||
SaSsoManager.printNoCheckSignWarningByRuntime();
|
||||
}
|
||||
|
||||
// step.2 单点注销
|
||||
ssoServerTemplate.ssoLogout(loginId);
|
||||
|
||||
// 响应
|
||||
return SaResult.ok();
|
||||
// 处理消息
|
||||
SaSsoMessage message = new SaSsoMessage(paramMap);
|
||||
if( ! ssoServerTemplate.messageHolder.hasHandle(message.getType())) {
|
||||
return SaResult.error("未能找到消息处理器: " + message.getType());
|
||||
}
|
||||
return ssoServerTemplate.handleMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装:单点注销成功后返回结果
|
||||
* @param req SaRequest对象
|
||||
* @param res SaResponse对象
|
||||
* @return 返回结果
|
||||
*/
|
||||
public Object ssoLogoutBack(SaRequest req, SaResponse res) {
|
||||
return SaSsoProcessorHelper.ssoLogoutBack(req, res, ssoServerTemplate.paramName);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,11 +22,13 @@ import cn.dev33.satoken.sso.SaSsoManager;
|
||||
import cn.dev33.satoken.sso.config.SaSsoClientConfig;
|
||||
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
|
||||
import cn.dev33.satoken.sso.exception.SaSsoException;
|
||||
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||
import cn.dev33.satoken.sso.message.handle.client.SaSsoMessageLogoutCallHandle;
|
||||
import cn.dev33.satoken.sso.util.SaSsoConsts;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Sa-Token SSO 模板方法类 (Client端)
|
||||
@ -36,12 +38,8 @@ import java.util.TreeMap;
|
||||
*/
|
||||
public class SaSsoClientTemplate extends SaSsoTemplate {
|
||||
|
||||
/**
|
||||
* 获取底层使用的SsoClient配置对象
|
||||
* @return /
|
||||
*/
|
||||
public SaSsoClientConfig getClientConfig() {
|
||||
return SaSsoManager.getClientConfig();
|
||||
public SaSsoClientTemplate() {
|
||||
super.messageHolder.addHandle(new SaSsoMessageLogoutCallHandle());
|
||||
}
|
||||
|
||||
|
||||
@ -66,7 +64,7 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
|
||||
*/
|
||||
public Object getData(String path, Map<String, Object> paramMap) {
|
||||
String url = buildCustomPathUrl(path, paramMap);
|
||||
return getClientConfig().sendHttp.apply(url);
|
||||
return request(url);
|
||||
}
|
||||
|
||||
// ---------------------- 构建URL ----------------------
|
||||
@ -108,56 +106,6 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
|
||||
return SaFoxUtil.joinParam(serverUrl, paramName.redirect, clientLoginUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:校验ticket的URL
|
||||
* <p> 在模式三下,Client端拿到Ticket后根据此地址向Server端发送请求,获取账号id
|
||||
* @param ticket ticket码
|
||||
* @param ssoLogoutCallUrl 单点注销时的回调URL
|
||||
* @return 构建完毕的URL
|
||||
*/
|
||||
public String buildCheckTicketUrl(String ticket, String ssoLogoutCallUrl) {
|
||||
|
||||
SaSsoClientConfig ssoConfig = getClientConfig();
|
||||
|
||||
// 1、url
|
||||
String url = ssoConfig.splicingCheckTicketUrl();
|
||||
|
||||
// 2、参数:client、ticket、ssoLogoutCall
|
||||
Map<String, Object> paramMap = new TreeMap<>();
|
||||
paramMap.put(paramName.ticket, ticket);
|
||||
paramMap.put(paramName.client, ssoConfig.getClient());
|
||||
paramMap.put(paramName.ssoLogoutCall, ssoLogoutCallUrl);
|
||||
|
||||
// 追加签名参数,并序列化为kv字符串
|
||||
String signParamStr = getSignTemplate(ssoConfig.getClient()).addSignParamsAndJoin(paramMap);
|
||||
|
||||
// 3、拼接
|
||||
return SaFoxUtil.joinParam(url, signParamStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:单点注销URL
|
||||
* @param loginId 要注销的账号id
|
||||
* @return 单点注销URL
|
||||
*/
|
||||
public String buildSloUrl(Object loginId) {
|
||||
// 获取所需对象
|
||||
SaSsoClientConfig ssoConfig = getClientConfig();
|
||||
String url = ssoConfig.splicingSloUrl();
|
||||
String currClient = ssoConfig.getClient();
|
||||
|
||||
// 组织请求参数
|
||||
Map<String, Object> paramMap = new TreeMap<>();
|
||||
paramMap.put(paramName.loginId, loginId);
|
||||
paramMap.put(paramName.client, currClient);
|
||||
|
||||
// 追加签名参数,并序列化为kv字符串
|
||||
String signParamsStr = getSignTemplate(currClient).addSignParamsAndJoin(paramMap);
|
||||
|
||||
// 拼接到 url 上
|
||||
return SaFoxUtil.joinParam(url, signParamsStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:Server端 getData 地址,带签名等参数
|
||||
* @param paramMap 查询参数
|
||||
@ -181,7 +129,7 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
|
||||
String url = path;
|
||||
if( ! url.startsWith("http") ) {
|
||||
String serverUrl = ssoConfig.getServerUrl();
|
||||
SaSsoException.notEmpty(serverUrl, "请先配置 sa-token.sso.server-url 地址", SaSsoErrorCode.CODE_30012);
|
||||
SaSsoException.notEmpty(serverUrl, "请先配置 sa-token.sso-client.server-url 地址", SaSsoErrorCode.CODE_30012);
|
||||
url = SaFoxUtil.spliceTwoUrl(serverUrl, path);
|
||||
}
|
||||
|
||||
@ -193,6 +141,86 @@ 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, ssoConfig.getClient());
|
||||
message.set(paramName.ticket, ticket);
|
||||
message.set(paramName.ssoLogoutCall, ssoLogoutCallUrl);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建消息:单点注销
|
||||
* @param loginId 要注销的账号 id
|
||||
* @return 单点注销URL
|
||||
*/
|
||||
public SaSsoMessage buildSloMessage(Object loginId) {
|
||||
SaSsoClientConfig ssoConfig = getClientConfig();
|
||||
SaSsoMessage message = new SaSsoMessage();
|
||||
message.setType(SaSsoConsts.MESSAGE_SIGNOUT);
|
||||
message.set(paramName.client, ssoConfig.getClient());
|
||||
message.set(paramName.loginId, loginId);
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 消息推送 -------------------
|
||||
|
||||
/**
|
||||
* 向 sso-server 推送消息
|
||||
*
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public String pushMessage(SaSsoMessage message) {
|
||||
SaSsoClientConfig ssoConfig = getClientConfig();
|
||||
|
||||
// 拼接 push-url 地址
|
||||
String pushUrl = ssoConfig.splicingPushUrl();
|
||||
SaSsoException.notTrue(! SaFoxUtil.isUrl(pushUrl), "无效 push-url 地址:" + pushUrl, SaSsoErrorCode.CODE_30023);
|
||||
|
||||
// 组织参数
|
||||
message.set(paramName.client, ssoConfig.getClient());
|
||||
message.checkType();
|
||||
String paramsStr = getSignTemplate(ssoConfig.getClient()).addSignParamsAndJoin(message);
|
||||
|
||||
// 发起请求
|
||||
String finalUrl = SaFoxUtil.joinParam(pushUrl, paramsStr);
|
||||
return request(finalUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向 sso-server 推送消息,并将返回值转为 SaResult
|
||||
*
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public SaResult pushMessageAsSaResult(SaSsoMessage message) {
|
||||
String res = pushMessage(message);
|
||||
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(res);
|
||||
return new SaResult(map);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- Bean 对象获取 -------------------
|
||||
|
||||
/**
|
||||
* 获取底层使用的SsoClient配置对象
|
||||
* @return /
|
||||
*/
|
||||
public SaSsoClientConfig getClientConfig() {
|
||||
return SaSsoManager.getClientConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取底层使用的 API 签名对象
|
||||
* @param client 指定客户端标识,填 null 代表获取默认的
|
||||
@ -212,18 +240,4 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
|
||||
return new SaSignTemplate(signConfig);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 发起请求 -------------------
|
||||
|
||||
/**
|
||||
* 发出请求,并返回 SaResult 结果
|
||||
* @param url 请求地址
|
||||
* @return 返回的结果
|
||||
*/
|
||||
public SaResult request(String url) {
|
||||
String body = getClientConfig().sendHttp.apply(url);
|
||||
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(body);
|
||||
return new SaResult(map);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ package cn.dev33.satoken.sso.template;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaSignConfig;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.sign.SaSignTemplate;
|
||||
import cn.dev33.satoken.sso.SaSsoManager;
|
||||
@ -25,10 +24,14 @@ import cn.dev33.satoken.sso.config.SaSsoClientModel;
|
||||
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.message.SaSsoMessage;
|
||||
import cn.dev33.satoken.sso.message.handle.server.SaSsoMessageCheckTicketHandle;
|
||||
import cn.dev33.satoken.sso.message.handle.server.SaSsoMessageSignoutHandle;
|
||||
import cn.dev33.satoken.sso.model.SaSsoClientInfo;
|
||||
import cn.dev33.satoken.sso.util.SaSsoConsts;
|
||||
import cn.dev33.satoken.strategy.SaStrategy;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -40,12 +43,9 @@ import java.util.*;
|
||||
*/
|
||||
public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
|
||||
/**
|
||||
* 获取底层使用的SsoServer配置对象
|
||||
* @return /
|
||||
*/
|
||||
public SaSsoServerConfig getServerConfig() {
|
||||
return SaSsoManager.getServerConfig();
|
||||
public SaSsoServerTemplate() {
|
||||
super.messageHolder.addHandle(new SaSsoMessageCheckTicketHandle());
|
||||
super.messageHolder.addHandle(new SaSsoMessageSignoutHandle());
|
||||
}
|
||||
|
||||
// ---------------------- Ticket 操作 ----------------------
|
||||
@ -165,7 +165,6 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
/**
|
||||
* 根据 账号id 创建一个 Ticket码
|
||||
* @param loginId 账号id
|
||||
@ -217,8 +216,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
} else {
|
||||
// 开始详细比对
|
||||
if(SaFoxUtil.notEquals(client, ticketClient)) {
|
||||
throw new SaSsoException("该 ticket 不属于 client=" + client + ", ticket 值: " + ticket)
|
||||
.setCode(SaSsoErrorCode.CODE_30011);
|
||||
throw new SaSsoException("该 ticket 不属于 client=" + client + ", ticket 值: " + ticket).setCode(SaSsoErrorCode.CODE_30011);
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,19 +239,28 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
return SaFoxUtil.getRandomString(64);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------- Client 信息获取 ----------------------
|
||||
|
||||
/**
|
||||
* 获取:所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
|
||||
* 获取所有 Client
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public List<SaSsoClientModel> getClients() {
|
||||
Map<String, SaSsoClientModel> clients = getServerConfig().getClients();
|
||||
return new ArrayList<>(clients.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用信息,无效 client 返回 null
|
||||
*
|
||||
* @param client /
|
||||
* @return /
|
||||
*/
|
||||
// public String getAllowUrl(String client) {
|
||||
// if(SaFoxUtil.isEmpty(client)) {
|
||||
// return getServerConfig().getAllowUrl();
|
||||
// } else {
|
||||
// return getClientNotNull(client).getAllowUrl();
|
||||
// }
|
||||
// }
|
||||
public SaSsoClientModel getClient(String client) {
|
||||
return getServerConfig().getClients().get(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用信息,无效 client 则抛出异常
|
||||
@ -295,13 +302,70 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用信息,无效 client 返回 null
|
||||
* 获取所有需要接收消息推送的 Client
|
||||
*
|
||||
* @param client /
|
||||
* @return /
|
||||
*/
|
||||
public SaSsoClientModel getClient(String client) {
|
||||
return getServerConfig().getClients().get(client);
|
||||
public List<SaSsoClientModel> getNeedPushClients() {
|
||||
List<SaSsoClientModel> list = new ArrayList<>();
|
||||
List<SaSsoClientModel> clients = getClients();
|
||||
for(SaSsoClientModel scm : clients) {
|
||||
if (scm.isValidNoticeUrl()) {
|
||||
list.add(scm);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 重定向 URL 构建与校验 -------------------
|
||||
|
||||
/**
|
||||
* 构建URL:Server端向Client下放ticket的地址
|
||||
* @param loginId 账号id
|
||||
* @param client 客户端标识
|
||||
* @param redirect Client端提供的重定向地址
|
||||
* @return see note
|
||||
*/
|
||||
public String buildRedirectUrl(Object loginId, String client, String redirect) {
|
||||
|
||||
// 校验 重定向地址 是否合法
|
||||
checkRedirectUrl(client, redirect);
|
||||
|
||||
// 删掉 旧Ticket
|
||||
deleteTicket(getTicketValue(loginId));
|
||||
|
||||
// 创建 新Ticket
|
||||
String ticket = createTicket(loginId, client);
|
||||
|
||||
// 构建 授权重定向地址 (Server端 根据此地址向 Client端 下放Ticket)
|
||||
return SaFoxUtil.joinParam(encodeBackParam(redirect), paramName.ticket, ticket);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对url中的back参数进行URL编码, 解决超链接重定向后参数丢失的bug
|
||||
* @param url url
|
||||
* @return 编码过后的url
|
||||
*/
|
||||
public String encodeBackParam(String url) {
|
||||
|
||||
// 获取back参数所在位置
|
||||
int index = url.indexOf("?" + paramName.back + "=");
|
||||
if(index == -1) {
|
||||
index = url.indexOf("&" + paramName.back + "=");
|
||||
if(index == -1) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
// 开始编码
|
||||
int length = paramName.back.length() + 2;
|
||||
String back = url.substring(index + length);
|
||||
back = SaFoxUtil.encodeUrl(back);
|
||||
|
||||
// 放回url中
|
||||
url = url.substring(0, index + length) + back;
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -402,55 +466,11 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------- SSO -------------------
|
||||
|
||||
// ------------------- 单点注销 -------------------
|
||||
|
||||
/**
|
||||
* 指定账号单点注销
|
||||
* @param loginId 指定账号
|
||||
*/
|
||||
public void ssoLogout(Object loginId) {
|
||||
|
||||
// 如果这个账号尚未登录,则无操作
|
||||
SaSession session = getStpLogic().getSessionByLoginId(loginId, false);
|
||||
if(session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// step.1 遍历通知 Client 端注销会话
|
||||
List<SaSsoClientInfo> scmList = session.get(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, ArrayList::new);
|
||||
scmList.forEach(scm -> {
|
||||
notifyClientLogout(loginId, scm, false);
|
||||
});
|
||||
|
||||
// step.2 Server端注销
|
||||
getStpLogic().logout(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算下一个 index 值
|
||||
* @param scmList /
|
||||
* @return /
|
||||
*/
|
||||
public int calcNextIndex(List<SaSsoClientInfo> scmList) {
|
||||
// 如果目前还没有任何登录记录,则直接返回0
|
||||
if(scmList == null || scmList.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
// 获取目前最大的index值
|
||||
int maxIndex = scmList.get(scmList.size() - 1).index;
|
||||
|
||||
// 如果已经是 int 最大值了,则直接返回0
|
||||
if(maxIndex == Integer.MAX_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 否则返回最大值+1
|
||||
maxIndex++;
|
||||
return maxIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指定账号id注册单点注销回调信息(模式三)
|
||||
* 为指定账号 id 注册单点注销回调信息(模式三)
|
||||
* @param loginId 账号id
|
||||
* @param client 指定客户端标识,可为null
|
||||
* @param sloCallbackUrl 单点注销时的回调URL
|
||||
@ -487,6 +507,52 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
session.set(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, scmList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算下一个 index 值
|
||||
* @param scmList /
|
||||
* @return /
|
||||
*/
|
||||
public int calcNextIndex(List<SaSsoClientInfo> scmList) {
|
||||
// 如果目前还没有任何登录记录,则直接返回0
|
||||
if(scmList == null || scmList.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
// 获取目前最大的index值
|
||||
int maxIndex = scmList.get(scmList.size() - 1).index;
|
||||
|
||||
// 如果已经是 int 最大值了,则直接返回0
|
||||
if(maxIndex == Integer.MAX_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 否则返回最大值+1
|
||||
maxIndex++;
|
||||
return maxIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定账号单点注销
|
||||
* @param loginId 指定账号
|
||||
*/
|
||||
public void ssoLogout(Object loginId) {
|
||||
|
||||
// 1、消息推送:单点注销
|
||||
pushToAllClientByLogoutCall(loginId);
|
||||
|
||||
// 2、SaSession 挂载的 Client 端注销会话
|
||||
SaSession session = getStpLogic().getSessionByLoginId(loginId, false);
|
||||
if(session == null) {
|
||||
return;
|
||||
}
|
||||
List<SaSsoClientInfo> scmList = session.get(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, ArrayList::new);
|
||||
scmList.forEach(scm -> {
|
||||
notifyClientLogout(loginId, scm, false);
|
||||
});
|
||||
|
||||
// 3、Server 端本身注销
|
||||
getStpLogic().logout(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知指定账号的指定客户端注销
|
||||
* @param loginId 指定账号
|
||||
@ -500,7 +566,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
return;
|
||||
}
|
||||
|
||||
// url
|
||||
// 如果此 Client 并没有注册 单点登录 回调地址,则立即返回
|
||||
String sloCallUrl = scm.getSloCallbackUrl();
|
||||
if(SaFoxUtil.isEmpty(sloCallUrl)) {
|
||||
return;
|
||||
@ -517,74 +583,102 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
String finalUrl = SaFoxUtil.joinParam(sloCallUrl, signParamsStr);
|
||||
|
||||
// 发起请求
|
||||
getServerConfig().sendHttp.apply(finalUrl);
|
||||
request(finalUrl);
|
||||
}
|
||||
|
||||
// ---------------------- 构建URL ----------------------
|
||||
|
||||
// ------------------- 消息推送 -------------------
|
||||
|
||||
/**
|
||||
* 构建URL:Server端向Client下放ticket的地址
|
||||
* @param loginId 账号id
|
||||
* @param client 客户端标识
|
||||
* @param redirect Client端提供的重定向地址
|
||||
* @return see note
|
||||
* 向指定 Client 推送消息
|
||||
* @param clientModel /
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public String buildRedirectUrl(Object loginId, String client, String redirect) {
|
||||
|
||||
// 校验 重定向地址 是否合法
|
||||
checkRedirectUrl(client, redirect);
|
||||
|
||||
// 删掉 旧Ticket
|
||||
deleteTicket(getTicketValue(loginId));
|
||||
|
||||
// 创建 新Ticket
|
||||
String ticket = createTicket(loginId, client);
|
||||
|
||||
// 构建 授权重定向地址 (Server端 根据此地址向 Client端 下放Ticket)
|
||||
return SaFoxUtil.joinParam(encodeBackParam(redirect), paramName.ticket, ticket);
|
||||
public String pushMessage(SaSsoClientModel clientModel, SaSsoMessage message) {
|
||||
message.checkType();
|
||||
String noticeUrl = clientModel.splicingNoticeUrl();
|
||||
String paramsStr = getSignTemplate(clientModel.getClient()).addSignParamsAndJoin(message);
|
||||
String finalUrl = SaFoxUtil.joinParam(noticeUrl, paramsStr);
|
||||
return request(finalUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对url中的back参数进行URL编码, 解决超链接重定向后参数丢失的bug
|
||||
* @param url url
|
||||
* @return 编码过后的url
|
||||
* 向指定 client 推送消息,并将返回值转为 SaResult
|
||||
*
|
||||
* @param clientModel /
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public String encodeBackParam(String url) {
|
||||
public SaResult pushMessageAsSaResult(SaSsoClientModel clientModel, SaSsoMessage message) {
|
||||
String res = pushMessage(clientModel, message);
|
||||
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(res);
|
||||
return new SaResult(map);
|
||||
}
|
||||
|
||||
// 获取back参数所在位置
|
||||
int index = url.indexOf("?" + paramName.back + "=");
|
||||
if(index == -1) {
|
||||
index = url.indexOf("&" + paramName.back + "=");
|
||||
if(index == -1) {
|
||||
return url;
|
||||
/**
|
||||
* 向指定 Client 推送消息
|
||||
* @param client /
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public String pushMessage(String client, SaSsoMessage message) {
|
||||
return pushMessage(getClientNotNull(client), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定 client 推送消息,并将返回值转为 SaResult
|
||||
*
|
||||
* @param client /
|
||||
* @param message /
|
||||
* @return /
|
||||
*/
|
||||
public SaResult pushMessageAsSaResult(String client, SaSsoMessage message) {
|
||||
String res = pushMessage(client, message);
|
||||
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(res);
|
||||
return new SaResult(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向所有 Client 推送消息
|
||||
*
|
||||
* @param message /
|
||||
*/
|
||||
public void pushToAllClient(SaSsoMessage message) {
|
||||
List<SaSsoClientModel> mode3Clients = getNeedPushClients();
|
||||
for (SaSsoClientModel client : mode3Clients) {
|
||||
pushMessage(client, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向所有 Client 推送消息:单点注销回调
|
||||
*
|
||||
* @param loginId /
|
||||
*/
|
||||
public void pushToAllClientByLogoutCall(Object loginId) {
|
||||
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);
|
||||
pushMessage(client, message);
|
||||
}
|
||||
}
|
||||
|
||||
// 开始编码
|
||||
int length = paramName.back.length() + 2;
|
||||
String back = url.substring(index + length);
|
||||
back = SaFoxUtil.encodeUrl(back);
|
||||
|
||||
// 放回url中
|
||||
url = url.substring(0, index + length) + back;
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------- 重构 ----------------------
|
||||
|
||||
// ------------------- Bean 获取 -------------------
|
||||
|
||||
/**
|
||||
* 校验 Ticket 码,获取账号id,如果此ticket是有效的,则立即删除
|
||||
* @param ticket Ticket码
|
||||
* @param client client 标识
|
||||
* 获取底层使用的SsoServer配置对象
|
||||
* @return /
|
||||
*/
|
||||
public void checkTicketVerifySign(SaRequest req, String ticket, String client) {
|
||||
SaSignTemplate signTemplate = getSignTemplate(client);
|
||||
signTemplate.checkRequest(req, paramName.client, paramName.ticket, paramName.ssoLogoutCall);
|
||||
public SaSsoServerConfig getServerConfig() {
|
||||
return SaSsoManager.getServerConfig();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取底层使用的 API 签名对象
|
||||
* @param client 指定客户端标识,填 null 代表获取默认的
|
||||
@ -609,8 +703,6 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ------------------- 返回相应key -------------------
|
||||
|
||||
/**
|
||||
|
@ -17,10 +17,15 @@ package cn.dev33.satoken.sso.template;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.sign.SaSignTemplate;
|
||||
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 模板方法类 (公共端)
|
||||
@ -78,4 +83,40 @@ public class SaSsoTemplate {
|
||||
return SaManager.getSaSignTemplate();
|
||||
}
|
||||
|
||||
// ----------- 消息处理
|
||||
|
||||
public SaSsoMessageHolder messageHolder = new SaSsoMessageHolder();
|
||||
|
||||
/**
|
||||
* 发送 Http 请求
|
||||
*
|
||||
* @param url /
|
||||
* @return /
|
||||
*/
|
||||
public String request(String url) {
|
||||
return SaManager.getSaHttpTemplate().get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 Http 请求,并将响应结果转换为 SaResult
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @return 返回的结果
|
||||
*/
|
||||
public SaResult requestAsSaResult(String url) {
|
||||
String body = request(url);
|
||||
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(body);
|
||||
return new SaResult(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理指定消息
|
||||
*
|
||||
* @param message /
|
||||
*/
|
||||
public Object handleMessage(SaSsoMessage message) {
|
||||
return messageHolder.handleMessage(this, message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -95,16 +95,6 @@ public class SaSsoUtil {
|
||||
return SaSsoServerProcessor.instance.ssoServerTemplate.checkTicket(ticket, client);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 获取:所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
|
||||
// *
|
||||
// * @param client 应用标识
|
||||
// * @return /
|
||||
// */
|
||||
// public static String getAllowUrl(String client) {
|
||||
// return SaSsoServerProcessor.instance.ssoServerTemplate.getAllowUrl(client);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 校验重定向url合法性
|
||||
*
|
||||
@ -117,16 +107,6 @@ public class SaSsoUtil {
|
||||
|
||||
|
||||
// ------------------- SSO 模式三 -------------------
|
||||
|
||||
/**
|
||||
* 构建URL:校验ticket的URL
|
||||
* @param ticket ticket码
|
||||
* @param ssoLogoutCallUrl 单点注销时的回调URL
|
||||
* @return 构建完毕的URL
|
||||
*/
|
||||
public static String buildCheckTicketUrl(String ticket, String ssoLogoutCallUrl) {
|
||||
return SaSsoClientProcessor.instance.ssoClientTemplate.buildCheckTicketUrl(ticket, ssoLogoutCallUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指定账号id注册单点注销回调URL
|
||||
@ -138,15 +118,6 @@ public class SaSsoUtil {
|
||||
SaSsoServerProcessor.instance.ssoServerTemplate.registerSloCallbackUrl(loginId, client, sloCallbackUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:单点注销URL
|
||||
* @param loginId 要注销的账号id
|
||||
* @return 单点注销URL
|
||||
*/
|
||||
public static String buildSloUrl(Object loginId) {
|
||||
return SaSsoClientProcessor.instance.ssoClientTemplate.buildSloUrl(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定账号单点注销 (以Server方发起)
|
||||
* @param loginId 指定账号
|
||||
|
@ -55,6 +55,18 @@ 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";
|
||||
|
||||
/** 消息类型:单点注销 */
|
||||
public static final String MESSAGE_SIGNOUT = "signout";
|
||||
|
||||
/** 消息类型:单点注销回调 */
|
||||
public static final String MESSAGE_LOGOUT_CALL = "logoutCall";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user