SSO 三种模式

This commit is contained in:
click33
2021-06-29 23:32:35 +08:00
parent 33318c6835
commit d2e00b341d
73 changed files with 1908 additions and 246 deletions

View File

@@ -25,23 +25,21 @@ public class SaSsoConfig {
public String secretkey;
/**
* SSO-Server端授权地址
* SSO-Server端 单点登录地址
*/
public String serverUrl;
public String authUrl;
/**
* @return SSO-Server端授权地址
* SSO-Server端 Ticket校验地址 [模式三专用配置]
*/
public String getServerUrl() {
return serverUrl;
}
public String checkTicketUrl;
/**
* @param serverUrl SSO-Server端授权地址
* SSO-Server端 单点注销地址 [模式三专用配置]
*/
public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
public String sloUrl;
/**
* @return Ticket有效期 (单位: 秒)
@@ -91,13 +89,54 @@ public class SaSsoConfig {
return this;
}
/**
* @return SSO-Server端 单点登录地址
*/
public String getAuthUrl() {
return authUrl;
}
/**
* @param authUrl SSO-Server端 单点登录地址
*/
public void setAuthUrl(String authUrl) {
this.authUrl = authUrl;
}
/**
* @return SSO-Server端Ticket校验地址
*/
public String getCheckTicketUrl() {
return checkTicketUrl;
}
/**
* @param checkTicketUrl SSO-Server端Ticket校验地址
*/
public void setCheckTicketUrl(String checkTicketUrl) {
this.checkTicketUrl = checkTicketUrl;
}
/**
* @return SSO-Server端单点注销地址
*/
public String getSloUrl() {
return sloUrl;
}
/**
* @param sloUrl SSO-Server端单点注销地址
*/
public void setSloUrl(String sloUrl) {
this.sloUrl = sloUrl;
}
@Override
public String toString() {
return "SaSsoConfig [ticketTimeout=" + ticketTimeout + ", allowUrl=" + allowUrl + ", secretkey=" + secretkey
+ ", serverUrl=" + serverUrl + "]";
+ ", authUrl=" + authUrl + ", checkTicketUrl=" + checkTicketUrl + ", sloUrl=" + sloUrl + "]";
}
/**
* 以数组形式写入允许的授权回调地址

View File

@@ -15,5 +15,17 @@ public class SaSsoConsts {
/** back参数名称 */
public static final String BACK_NAME = "back";
/** loginId参数名称 */
public static final String LOGIN_ID_NAME = "loginId";
/** secretkey参数名称 */
public static final String SECRETKEY = "secretkey";
/** Client端单点注销时-回调URL 参数名称 */
public static final String SLO_CALLBACK_NAME = "sloCallback";
/** Client端单点注销回调URL的Set集合存储在Session中使用的key */
public static final String SLO_CALLBACK_SET_KEY = "SLO_CALLBACK_SET_KEY_";
}

View File

@@ -1,10 +1,14 @@
package cn.dev33.satoken.sso;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;
/**
@@ -41,14 +45,14 @@ public interface SaSsoInterface {
}
/**
* 根据 账号id & 重定向地址,构建[SSO-Client端-重定向地址]
* 构建URLServer端向Client下放ticke的地址
* @param loginId 账号id
* @param redirect 重定向地址
* @return [SSO-Client端-重定向地址]
* @param redirect Client端提供的重定向地址
* @return see note
*/
public default String buildRedirectUrl(Object loginId, String redirect) {
// 校验授权地址
checkAuthUrl(redirect);
// 校验重定向地址
checkRedirectUrl(redirect);
// 删掉旧ticket
String oldTicket = SaManager.getSaTokenDao().get(splicingKeyIdToTicket(loginId));
@@ -61,7 +65,7 @@ public interface SaSsoInterface {
// 构建 授权重定向地址
redirect = encodeBackParam(redirect);
String redirectUrl = SaFoxUtil.joinParam(redirect, SaSsoConsts.TICKET_NAME + "=" + ticket);
String redirectUrl = SaFoxUtil.joinParam(redirect, SaSsoConsts.TICKET_NAME, ticket);
return redirectUrl;
}
@@ -87,10 +91,23 @@ public interface SaSsoInterface {
}
/**
* 校验url合法性
* @param url 地址
* 校验ticket码获取账号id如果ticket可以有效则立刻删除
* @param ticket Ticket码
* @return 账号id
*/
public default void checkAuthUrl(String url) {
public default Object checkTicket(String ticket) {
Object loginId = getLoginId(ticket);
if(loginId != null) {
deleteTicket(ticket);
}
return loginId;
}
/**
* 校验重定向url合法性
* @param url 下放ticket的url地址
*/
public default void checkRedirectUrl(String url) {
// 1、是否是一个有效的url
if(SaFoxUtil.isUrl(url) == false) {
@@ -122,15 +139,15 @@ public interface SaSsoInterface {
*/
public default String buildServerAuthUrl(String clientLoginUrl, String back) {
// 服务端认证地址
String serverUrl = SaManager.getConfig().getSso().getServerUrl();
String serverUrl = SaManager.getConfig().getSso().getAuthUrl();
// 对back地址编码
back = (back == null ? "" : back);
back = SaFoxUtil.encodeUrl(back);
// 拼接最终地址格式serverAuthUrl = http://xxx.com?redirectUrl=xxx.com?back=xxx.com
clientLoginUrl = SaFoxUtil.joinParam(clientLoginUrl, SaSsoConsts.BACK_NAME + "=" + back);
String serverAuthUrl = SaFoxUtil.joinParam(serverUrl, SaSsoConsts.REDIRECT_NAME + "=" + clientLoginUrl);
// 拼接最终地址,格式示例serverAuthUrl = http://xxx.com?redirectUrl=xxx.com?back=xxx.com
clientLoginUrl = SaFoxUtil.joinParam(clientLoginUrl, SaSsoConsts.BACK_NAME, back);
String serverAuthUrl = SaFoxUtil.joinParam(serverUrl, SaSsoConsts.REDIRECT_NAME, clientLoginUrl);
// 返回
return serverAuthUrl;
@@ -171,6 +188,101 @@ public interface SaSsoInterface {
return SaFoxUtil.getRandomString(64);
}
// ------------------- SSO 模式三 -------------------
/**
* 校验secretkey秘钥是否有效
* @param secretkey 秘钥
*/
public default void checkSecretkey(String secretkey) {
if(secretkey == null || secretkey.isEmpty() || secretkey.equals(SaManager.getConfig().getSso().getSecretkey()) == false) {
throw new SaTokenException("无效秘钥:" + secretkey);
}
}
/**
* 构建URL校验ticket的URL
* @param ticket ticket码
* @param sloCallbackUrl 单点注销时的回调URL
* @return 构建完毕的URL
*/
public default String buildCheckTicketUrl(String ticket, String sloCallbackUrl) {
String url = SaManager.getConfig().getSso().getCheckTicketUrl();
// 拼接ticket参数
url = SaFoxUtil.joinParam(url, SaSsoConsts.TICKET_NAME, ticket);
// 拼接单点注销时的回调URL
if(sloCallbackUrl != null) {
url = SaFoxUtil.joinParam(url, SaSsoConsts.SLO_CALLBACK_NAME, sloCallbackUrl);
}
// 返回
return url;
}
/**
* 为指定账号id注册单点注销回调URL
* @param loginId 账号id
* @param sloCallbackUrl 单点注销时的回调URL
*/
public default void registerSloCallbackUrl(Object loginId, String sloCallbackUrl) {
if(loginId == null || sloCallbackUrl == null || sloCallbackUrl.isEmpty()) {
return;
}
Set<String> urlSet = StpUtil.getSessionByLoginId(loginId).get(SaSsoConsts.SLO_CALLBACK_SET_KEY, ()-> new HashSet<String>());
urlSet.add(sloCallbackUrl);
StpUtil.getSessionByLoginId(loginId).set(SaSsoConsts.SLO_CALLBACK_SET_KEY, urlSet);
}
/**
* 循环调用Client端单点注销回调
* @param loginId 账号id
* @param fun 调用方法
*/
public default void forEachSloUrl(Object loginId, CallSloUrlFunction fun) {
String secretkey = SaManager.getConfig().getSso().getSecretkey();
Set<String> urlSet = StpUtil.getSessionByLoginId(loginId).get(SaSsoConsts.SLO_CALLBACK_SET_KEY,
() -> new HashSet<String>());
for (String url : urlSet) {
// 拼接login参数、秘钥参数
url = SaFoxUtil.joinParam(url, SaSsoConsts.LOGIN_ID_NAME, loginId);
url = SaFoxUtil.joinParam(url, SaSsoConsts.SECRETKEY, secretkey);
// 调用
fun.run(url);
}
}
/**
* 构建URL单点注销URL
* @param loginId 要注销的账号id
* @return 单点注销URL
*/
public default String buildSloUrl(Object loginId) {
SaSsoConfig ssoConfig = SaManager.getConfig().getSso();
String url = ssoConfig.getSloUrl();
url = SaFoxUtil.joinParam(url, SaSsoConsts.LOGIN_ID_NAME, loginId);
url = SaFoxUtil.joinParam(url, SaSsoConsts.SECRETKEY, ssoConfig.getSecretkey());
return url;
}
/**
* 指定账号单点注销
* @param secretkey 校验秘钥
* @param loginId 指定账号
* @param fun 调用方法
*/
public default void singleLogout(String secretkey, Object loginId, CallSloUrlFunction fun) {
// step.1 校验秘钥
checkSecretkey(secretkey);
// step.2 遍历通知Client端注销会话
forEachSloUrl(loginId, fun);
// step.3 Server端注销
StpUtil.logoutByLoginId(loginId);
}
// ------------------- 返回相应key -------------------
@@ -193,4 +305,14 @@ public interface SaSsoInterface {
}
@FunctionalInterface
static interface CallSloUrlFunction{
/**
* 调用function
* @param url 注销回调URL
*/
public void run(String url);
}
}

View File

@@ -1,5 +1,7 @@
package cn.dev33.satoken.sso;
import cn.dev33.satoken.sso.SaSsoInterface.CallSloUrlFunction;
/**
* Sa-Token-SSO 单点登录工具类
* @author kong
@@ -30,10 +32,10 @@ public class SaSsoUtil {
}
/**
* 根据 账号id & 重定向地址,构建[SSO-Client端-重定向地址]
* 构建URLServer端向Client下放ticke的地址
* @param loginId 账号id
* @param redirect 重定向地址
* @return [SSO-Client端-重定向地址]
* @param redirect Client端提供的重定向地址
* @return see note
*/
public static String buildRedirectUrl(Object loginId, String redirect) {
return saSsoInterface.buildRedirectUrl(loginId, redirect);
@@ -56,13 +58,22 @@ public class SaSsoUtil {
public static <T> T getLoginId(String ticket, Class<T> cs) {
return saSsoInterface.getLoginId(ticket, cs);
}
/**
* 校验ticket码获取账号id如果ticket可以有效则立刻删除
* @param ticket Ticket码
* @return 账号id
*/
public static Object checkTicket(String ticket) {
return saSsoInterface.checkTicket(ticket);
}
/**
* 校验url合法性
* @param url 地址
* 校验重定向url合法性
* @param url 下放ticket的url地址
*/
public static void checkAuthUrl(String url) {
saSsoInterface.checkAuthUrl(url);
saSsoInterface.checkRedirectUrl(url);
}
/**
@@ -74,5 +85,63 @@ public class SaSsoUtil {
public static String buildServerAuthUrl(String clientLoginUrl, String back) {
return saSsoInterface.buildServerAuthUrl(clientLoginUrl, back);
}
// ------------------- SSO 模式三 -------------------
/**
* 校验secretkey秘钥是否有效
* @param secretkey 秘钥
*/
public static void checkSecretkey(String secretkey) {
saSsoInterface.checkSecretkey(secretkey);
}
/**
* 构建URL校验ticket的URL
* @param ticket ticket码
* @param sloCallbackUrl 单点注销时的回调URL (如果不需要单点注销功能此值可以填null)
* @return 构建完毕的URL
*/
public static String buildCheckTicketUrl(String ticket, String sloCallbackUrl) {
return saSsoInterface.buildCheckTicketUrl(ticket, sloCallbackUrl);
}
/**
* 为指定账号id注册单点注销回调URL
* @param loginId 账号id
* @param sloCallbackUrl 单点注销时的回调URL
*/
public static void registerSloCallbackUrl(Object loginId, String sloCallbackUrl) {
saSsoInterface.registerSloCallbackUrl(loginId, sloCallbackUrl);
}
/**
* 循环调用Client端单点注销回调
* @param loginId 账号id
* @param fun 调用方法
*/
public static void forEachSloUrl(Object loginId, CallSloUrlFunction fun) {
saSsoInterface.forEachSloUrl(loginId, fun);
}
/**
* 构建URL单点注销URL
* @param loginId 要注销的账号id
* @return 单点注销URL
*/
public static String buildSloUrl(Object loginId) {
return saSsoInterface.buildSloUrl(loginId);
}
/**
* 指定账号单点注销
* @param secretkey 校验秘钥
* @param loginId 指定账号
* @param fun 调用方法
*/
public static void singleLogout(String secretkey, Object loginId, CallSloUrlFunction fun) {
saSsoInterface.singleLogout(secretkey, loginId, fun);
}
}

View File

@@ -226,6 +226,21 @@ public class SaFoxUtil {
// 正常情况下, 代码不可能执行到此
return url;
}
/**
* 在url上拼接上kv参数并返回
* @param url url
* @param key 参数名称
* @param value 参数值
* @return 拼接后的url字符串
*/
public static String joinParam(String url, String key, Object value) {
// 如果参数为空, 直接返回
if(isEmpty(url) || isEmpty(key) || isEmpty(String.valueOf(value))) {
return url;
}
return joinParam(url, key + "=" + value);
}
/**
* 将数组的所有元素使用逗号拼接在一起