将 sso 模块从 core 包下拆分出来,并细分 sso 模块异常

This commit is contained in:
click33 2022-04-26 00:47:31 +08:00
parent f5cbe0616e
commit a3c8b2ade2
39 changed files with 511 additions and 117 deletions

View File

@ -35,7 +35,7 @@ public class SaTokenConfig implements Serializable {
/**
* 同一账号最大登录数量-1代表不限 只有在 isConcurrent=true, isShare=false 时此配置才有效
*/
private int maxLoginCount = 10;
private int maxLoginCount = 12;
/** 是否尝试从请求体里读取token */
private Boolean isReadBody = true;
@ -93,11 +93,6 @@ public class SaTokenConfig implements Serializable {
*/
public SaCookieConfig cookie = new SaCookieConfig();
/**
* SSO单点登录配置对象
*/
public SaSsoConfig sso = new SaSsoConfig();
/**
* @return token名称 (同时也是cookie名称)
@ -439,22 +434,6 @@ public class SaTokenConfig implements Serializable {
return this;
}
/**
* @return SSO单点登录配置对象
*/
public SaSsoConfig getSso() {
return sso;
}
/**
* @param sso SSO单点登录配置对象
* @return 对象自身
*/
public SaTokenConfig setSso(SaSsoConfig sso) {
this.sso = sso;
return this;
}
/**
* @return Cookie 全局配置对象
*/
@ -495,7 +474,6 @@ public class SaTokenConfig implements Serializable {
+ ", basic=" + basic
+ ", currDomain=" + currDomain
+ ", checkIdToken=" + checkIdToken
+ ", sso=" + sso
+ ", cookie=" + cookie
+ "]";
}

View File

@ -16,13 +16,13 @@ public class NotPermissionException extends SaTokenException {
private static final long serialVersionUID = 6806129545290130141L;
/** 权限码 */
private String code;
private String permission;
/**
* @return 获得权限码
* @return 获得具体缺少的权限码
*/
public String getCode() {
return code;
public String getPermission() {
return permission;
}
/**
@ -39,14 +39,23 @@ public class NotPermissionException extends SaTokenException {
return loginType;
}
public NotPermissionException(String code) {
this(code, StpUtil.stpLogic.loginType);
public NotPermissionException(String permission) {
this(permission, StpUtil.stpLogic.loginType);
}
public NotPermissionException(String code, String loginType) {
super("无此权限:" + code);
this.code = code;
public NotPermissionException(String permission, String loginType) {
super("无此权限:" + permission);
this.permission = permission;
this.loginType = loginType;
}
/**
* <h1> 警告 v1.30+ 版本起获取异常权限码由 getCode() 更改为 getPermission()请及时更换
* @return 获得权限码
*/
@Deprecated
public int getCode() {
return super.getCode();
}
}

View File

@ -0,0 +1,14 @@
package cn.dev33.satoken.exception;
/**
* 定义所有异常细分状态码
*
* @author kong
* @date: 2022-4-25
*/
public class SaExceptionCode {
/** 代表未指定异常细分状态码 */
public static final int CODE_UNDEFINED = -1;
}

View File

@ -16,6 +16,22 @@ public class SaTokenException extends RuntimeException {
*/
private static final long serialVersionUID = 6806129545290130132L;
/**
* 异常细分状态码
*/
private int code = SaExceptionCode.CODE_UNDEFINED;
/**
* 构建一个异常
*
* @param code 异常细分状态码
*/
public SaTokenException(int code) {
super();
this.code = code;
}
/**
* 构建一个异常
*
@ -25,6 +41,17 @@ public class SaTokenException extends RuntimeException {
super(message);
}
/**
* 构建一个异常
*
* @param code 异常细分状态码
* @param message 异常信息
*/
public SaTokenException(int code, String message) {
super(message);
this.code = code;
}
/**
* 构建一个异常
*
@ -44,6 +71,23 @@ public class SaTokenException extends RuntimeException {
super(message, cause);
}
/**
* @return 异常细分状态码
*/
public int getCode() {
return code;
}
/**
* 写入异常细分状态码
* @param code 异常细分状态码
* @return 对象自身
*/
public SaTokenException setCode(int code) {
this.code = code;
return this;
}
/**
* 如果flag==true则抛出message异常
* @param flag 标记

View File

@ -320,10 +320,7 @@ public class StpLogic {
if(getConfigOfIsShare()) {
tokenValue = getTokenValueByLoginId(id, loginModel.getDeviceOrDefault());
} else {
// 如果配置为不共享token需要检查会话是否超出 max-login-count
if(config.getMaxLoginCount() != -1) {
logoutByRetainCount(id, null, config.getMaxLoginCount() - 1);
}
//
}
} else {
// --- 如果不允许并发登录则将这个账号的历史登录标记为被顶下线
@ -354,6 +351,11 @@ public class StpLogic {
// $$ 通知监听器账号xxx 登录成功
SaManager.getSaTokenListener().doLogin(loginType, id, loginModel);
// 检查此账号会话数量是否超出最大值
if(config.getMaxLoginCount() != -1) {
logoutByMaxLoginCount(id, session, null, config.getMaxLoginCount());
}
// 返回Token
return tokenValue;
@ -399,28 +401,11 @@ public class StpLogic {
* @param device 设备类型 (填null代表注销所有设备类型)
*/
public void logout(Object loginId, String device) {
logoutByRetainCount(loginId, device, 0);
}
/**
* 会话注销根据账号id 设备类型 保留数量
*
* @param loginId 账号id
* @param device 设备类型 (填null代表注销所有设备类型)
* @param retainCount 保留最近的n次登录
*/
public void logoutByRetainCount(Object loginId, String device, int retainCount) {
SaSession session = getSessionByLoginId(loginId, false);
if(session != null) {
List<TokenSign> list = session.tokenSignListCopyByDevice(device);
// 遍历操作
for (int i = 0; i < list.size(); i++) {
// 只操作前n条
if(i >= list.size() - retainCount) {
continue;
}
for (TokenSign tokenSign: session.tokenSignListCopyByDevice(device)) {
// 清理 token签名token最后活跃时间
String tokenValue = list.get(i).getValue();
String tokenValue = tokenSign.getValue();
session.removeTokenSign(tokenValue);
clearLastActivity(tokenValue);
// 删除Token-Id映射 & 清除Token-Session
@ -433,6 +418,41 @@ public class StpLogic {
}
}
/**
* 会话注销根据账号id 设备类型 最大同时在线数量
*
* @param loginId 账号id
* @param session 此账号的 Session 对象可填写null框架将自动获取
* @param device 设备类型 (填null代表注销所有设备类型)
* @param maxLoginCount 保留最近的几次登录
*/
public void logoutByMaxLoginCount(Object loginId, SaSession session, String device, int maxLoginCount) {
if(session == null) {
session = getSessionByLoginId(loginId, false);
if(session == null) {
return;
}
}
List<TokenSign> list = session.tokenSignListCopyByDevice(device);
// 遍历操作
for (int i = 0; i < list.size(); i++) {
// 只操作前n条
if(i >= list.size() - maxLoginCount) {
continue;
}
// 清理 token签名token最后活跃时间
String tokenValue = list.get(i).getValue();
session.removeTokenSign(tokenValue);
clearLastActivity(tokenValue);
// 删除Token-Id映射 & 清除Token-Session
deleteTokenToIdMapping(tokenValue);
deleteTokenSession(tokenValue);
SaManager.getSaTokenListener().doLogout(loginType, loginId, tokenValue);
}
// 注销 Session
session.logoutByTokenSignCountToZero();
}
/**
* 会话注销根据指定 Token
*

View File

@ -36,7 +36,7 @@ public class GlobalException {
aj = AjaxJson.getNotJur("无此角色:" + ee.getRole());
} else if(e instanceof NotPermissionException) { // 如果是权限异常
NotPermissionException ee = (NotPermissionException) e;
aj = AjaxJson.getNotJur("无此权限:" + ee.getCode());
aj = AjaxJson.getNotJur("无此权限:" + ee.getPermission());
} else { // 普通异常, 输出500 + 异常信息
aj = AjaxJson.getError(e.getMessage());
}

View File

@ -31,7 +31,7 @@ public class GlobalException implements EventListener<Throwable> {
aj = AjaxJson.getNotJur("无此角色:" + ee.getRole());
} else if (e instanceof NotPermissionException) { // 如果是权限异常
NotPermissionException ee = (NotPermissionException) e;
aj = AjaxJson.getNotJur("无此权限:" + ee.getCode());
aj = AjaxJson.getNotJur("无此权限:" + ee.getPermission());
} else if (e instanceof DisableLoginException) { // 如果是被封禁异常
DisableLoginException ee = (DisableLoginException) e;
aj = AjaxJson.getNotJur("账号被封禁:" + ee.getDisableTime() + "秒后解封");

View File

@ -42,7 +42,7 @@ public class GlobalException {
}
else if(e instanceof NotPermissionException) { // 如果是权限异常
NotPermissionException ee = (NotPermissionException) e;
aj = AjaxJson.getNotJur("无此权限:" + ee.getCode());
aj = AjaxJson.getNotJur("无此权限:" + ee.getPermission());
}
else if(e instanceof DisableLoginException) { // 如果是被封禁异常
DisableLoginException ee = (DisableLoginException) e;

View File

@ -34,7 +34,14 @@
<version>${sa-token-version}</version>
</dependency>
<!-- Sa-Token整合redis (使用jackson序列化方式) -->
<!-- Sa-Token 插件整合SSO -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- Sa-Token 插件整合redis (使用jackson序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>

View File

@ -7,7 +7,7 @@ import org.springframework.web.servlet.ModelAndView;
import com.ejlchina.okhttps.OkHttps;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.sso.SaSsoHandle;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
@ -34,15 +34,15 @@ public class SsoServerController {
// 配置SSO相关参数
@Autowired
private void configSso(SaTokenConfig cfg) {
private void configSso(SaSsoConfig sso) {
// 配置未登录时返回的View
cfg.sso.setNotLoginView(() -> {
sso.setNotLoginView(() -> {
return new ModelAndView("sa-login.html");
});
// 配置登录处理函数
cfg.sso.setDoLoginHandle((name, pwd) -> {
sso.setDoLoginHandle((name, pwd) -> {
// 此处仅做模拟登录真实环境应该查询数据进行登录
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
@ -52,7 +52,7 @@ public class SsoServerController {
});
// 配置 Http 请求处理器 在模式三的单点注销功能下用到如不需要可以注释掉
cfg.sso.setSendHttp(url -> {
sso.setSendHttp(url -> {
return OkHttps.sync(url).get().getBody().toString();
});
}

View File

@ -34,6 +34,13 @@
<version>${sa-token-version}</version>
</dependency>
<!-- Sa-Token 插件整合SSO -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- Sa-Token 整合redis (使用jackson序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>

View File

@ -4,7 +4,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.sso.SaSsoManager;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
@ -18,8 +18,8 @@ public class SsoClientController {
// SSO-Client端首页
@RequestMapping("/")
public String index() {
String authUrl = SaManager.getConfig().getSso().getAuthUrl();
String solUrl = SaManager.getConfig().getSso().getSloUrl();
String authUrl = SaSsoManager.getConfig().getAuthUrl();
String solUrl = SaSsoManager.getConfig().getSloUrl();
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

@ -34,6 +34,13 @@
<version>${sa-token-version}</version>
</dependency>
<!-- Sa-Token 插件整合SSO -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- Sa-Token 整合redis (使用jackson序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>

View File

@ -34,6 +34,13 @@
<version>${sa-token-version}</version>
</dependency>
<!-- Sa-Token 插件整合SSO -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- Sa-Token 整合redis (使用jackson序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>

View File

@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.RestController;
import com.ejlchina.okhttps.OkHttps;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.sso.SaSsoHandle;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.stp.StpUtil;
@ -43,9 +43,9 @@ public class SsoClientController {
// 配置SSO相关参数
@Autowired
private void configSso(SaTokenConfig cfg) {
private void configSso(SaSsoConfig sso) {
// 配置Http请求处理器
cfg.sso.setSendHttp(url -> {
sso.setSendHttp(url -> {
return OkHttps.sync(url).get().getBody().toString();
});
}

View File

@ -37,7 +37,7 @@ public class GlobalException {
aj = AjaxJson.getNotJur("无此角色:" + ee.getRole());
} else if(e instanceof NotPermissionException) { // 如果是权限异常
NotPermissionException ee = (NotPermissionException) e;
aj = AjaxJson.getNotJur("无此权限:" + ee.getCode());
aj = AjaxJson.getNotJur("无此权限:" + ee.getPermission());
} else if(e instanceof DisableLoginException) { // 如果是被封禁异常
DisableLoginException ee = (DisableLoginException) e;
aj = AjaxJson.getNotJur("账号被封禁:" + ee.getDisableTime() + "秒后解封");

View File

@ -79,7 +79,7 @@ PS两者的区别在于**`模式1会覆盖yml中的配置模式2会与y
| activityTimeout | long | -1 | token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒, 默认-1 代表不限制 (例如可以设置为1800代表30分钟内无操作就过期) [参考token有效期详解](/fun/token-timeout) |
| isConcurrent | Boolean | true | 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) |
| isShare | Boolean | true | 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) |
| maxLoginCount | int | 10 | 同一账号最大登录数量,-1代表不限 (只有在 isConcurrent=true, isShare=false 时此配置才有效) |
| maxLoginCount | int | 12 | 同一账号最大登录数量,-1代表不限 (只有在 isConcurrent=true, isShare=false 时此配置才有效) |
| isReadBody | Boolean | true | 是否尝试从 请求体 里读取 Token |
| isReadHead | Boolean | true | 是否尝试从 header 里读取 Token |
| isReadCookie | Boolean | true | 是否尝试从 cookie 里读取 Token |

13
sa-token-plugin/sa-token-sso/.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
target/
node_modules/
bin/
.settings/
unpackage/
.classpath
.project
.factorypath
.idea/
.iml

View File

@ -0,0 +1,30 @@
<?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-plugin</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>jar</packaging>
<name>sa-token-sso</name>
<artifactId>sa-token-sso</artifactId>
<description>sa-token realization sso</description>
<dependencies>
<!-- sa-token-core -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,5 +1,6 @@
package cn.dev33.satoken.config;
import java.io.Serializable;
import java.util.function.BiFunction;
import java.util.function.Function;

View File

@ -1,13 +1,13 @@
package cn.dev33.satoken.sso;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.sso.SaSsoConsts.Api;
import cn.dev33.satoken.sso.SaSsoConsts.ParamName;
import cn.dev33.satoken.sso.exception.SaSsoException;
import cn.dev33.satoken.sso.exception.SaSsoExceptionCode;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult;
@ -27,7 +27,7 @@ public class SaSsoHandle {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaSsoConfig cfg = SaManager.getConfig().getSso();
SaSsoConfig cfg = SaSsoManager.getConfig();
// ------------------ 路由分发 ------------------
@ -68,7 +68,7 @@ public class SaSsoHandle {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaSsoConfig cfg = SaManager.getConfig().getSso();
SaSsoConfig cfg = SaSsoManager.getConfig();
StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;
// ---------- 此处有两种情况分开处理
@ -98,7 +98,7 @@ public class SaSsoHandle {
public static Object ssoDoLogin() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaSsoConfig cfg = SaManager.getConfig().getSso();
SaSsoConfig cfg = SaSsoManager.getConfig();
// 处理
return cfg.getDoLoginHandle().apply(req.getParam(ParamName.name), req.getParam(ParamName.pwd));
@ -150,7 +150,7 @@ public class SaSsoHandle {
public static Object ssoServerLogout() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaSsoConfig cfg = SaManager.getConfig().getSso();
SaSsoConfig cfg = SaSsoManager.getConfig();
StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;
// 获取参数
@ -180,7 +180,7 @@ public class SaSsoHandle {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaSsoConfig cfg = SaManager.getConfig().getSso();
SaSsoConfig cfg = SaSsoManager.getConfig();
// ------------------ 路由分发 ------------------
@ -216,7 +216,7 @@ public class SaSsoHandle {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaSsoConfig cfg = SaManager.getConfig().getSso();
SaSsoConfig cfg = SaSsoManager.getConfig();
StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;
// 获取参数
@ -249,7 +249,7 @@ public class SaSsoHandle {
return res.redirect(back);
} else {
// 如果ticket无效:
throw new SaTokenException("无效ticket" + ticket);
throw new SaSsoException("无效ticket" + ticket).setCode(SaSsoExceptionCode.CODE_20004);
}
}
}
@ -279,7 +279,7 @@ public class SaSsoHandle {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaSsoConfig cfg = SaManager.getConfig().getSso();
SaSsoConfig cfg = SaSsoManager.getConfig();
StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;
// 如果未登录则无需注销
@ -347,7 +347,7 @@ public class SaSsoHandle {
* @return loginId
*/
public static Object checkTicket(String ticket, String currUri) {
SaSsoConfig cfg = SaManager.getConfig().getSso();
SaSsoConfig cfg = SaSsoManager.getConfig();
// --------- 两种模式
if(cfg.getIsHttp()) {
// 模式三使用http请求校验ticket

View File

@ -0,0 +1,31 @@
package cn.dev33.satoken.sso;
import cn.dev33.satoken.config.SaSsoConfig;
/**
* Sa-Token-SSO 模块 总控类
*
* @author kong
*
*/
public class SaSsoManager {
/**
* Sso 配置 Bean
*/
private static SaSsoConfig config;
public static SaSsoConfig getConfig() {
if (config == null) {
synchronized (SaSsoManager.class) {
if (config == null) {
setConfig(new SaSsoConfig());
}
}
}
return config;
}
public static void setConfig(SaSsoConfig config) {
SaSsoManager.config = config;
}
}

View File

@ -7,9 +7,10 @@ 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.session.SaSession;
import cn.dev33.satoken.sso.SaSsoConsts.ParamName;
import cn.dev33.satoken.sso.exception.SaSsoException;
import cn.dev33.satoken.sso.exception.SaSsoExceptionCode;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaFoxUtil;
@ -54,7 +55,7 @@ public class SaSsoTemplate {
* @param loginId 账号id
*/
public void saveTicket(String ticket, Object loginId) {
long ticketTimeout = SaManager.getConfig().getSso().getTicketTimeout();
long ticketTimeout = SaSsoManager.getConfig().getTicketTimeout();
SaManager.getSaTokenDao().set(splicingTicketSaveKey(ticket), String.valueOf(loginId), ticketTimeout);
}
@ -64,7 +65,7 @@ public class SaSsoTemplate {
* @param loginId 账号id
*/
public void saveTicketIndex(String ticket, Object loginId) {
long ticketTimeout = SaManager.getConfig().getSso().getTicketTimeout();
long ticketTimeout = SaSsoManager.getConfig().getTicketTimeout();
SaManager.getSaTokenDao().set(splicingTicketIndexKey(loginId), String.valueOf(ticket), ticketTimeout);
}
@ -160,7 +161,7 @@ public class SaSsoTemplate {
public String buildServerAuthUrl(String clientLoginUrl, String back) {
// 服务端认证地址
String serverUrl = SaManager.getConfig().getSso().getAuthUrl();
String serverUrl = SaSsoManager.getConfig().getAuthUrl();
// 对back地址编码
back = (back == null ? "" : back);
@ -210,7 +211,7 @@ public class SaSsoTemplate {
// 1是否是一个有效的url
if(SaFoxUtil.isUrl(url) == false) {
throw new SaTokenException("无效redirect" + url);
throw new SaSsoException("无效redirect" + url).setCode(SaSsoExceptionCode.CODE_20001);
}
// 2截取掉?后面的部分
@ -222,7 +223,7 @@ public class SaSsoTemplate {
// 3是否在[允许地址列表]之中
List<String> authUrlList = Arrays.asList(getAllowUrl().replaceAll(" ", "").split(","));
if(SaStrategy.me.hasElement.apply(authUrlList, url) == false) {
throw new SaTokenException("非法redirect" + url);
throw new SaSsoException("非法redirect" + url).setCode(SaSsoExceptionCode.CODE_20002);
}
// 校验通过
@ -235,7 +236,7 @@ public class SaSsoTemplate {
*/
public String getAllowUrl() {
// 默认从配置文件中返回
return SaManager.getConfig().getSso().getAllowUrl();
return SaSsoManager.getConfig().getAllowUrl();
}
/**
@ -271,9 +272,9 @@ public class SaSsoTemplate {
*/
public String buildUserinfoUrl(Object loginId) {
// 拼接
String userinfoUrl = SaManager.getConfig().getSso().getUserinfoUrl();
String userinfoUrl = SaSsoManager.getConfig().getUserinfoUrl();
userinfoUrl = SaFoxUtil.joinParam(userinfoUrl, ParamName.loginId, loginId);
userinfoUrl = SaFoxUtil.joinParam(userinfoUrl, ParamName.secretkey, SaManager.getConfig().getSso().getSecretkey());
userinfoUrl = SaFoxUtil.joinParam(userinfoUrl, ParamName.secretkey, SaSsoManager.getConfig().getSecretkey());
// 返回
return userinfoUrl;
}
@ -286,8 +287,8 @@ public class SaSsoTemplate {
* @param secretkey 秘钥
*/
public void checkSecretkey(String secretkey) {
if(secretkey == null || secretkey.isEmpty() || secretkey.equals(SaManager.getConfig().getSso().getSecretkey()) == false) {
throw new SaTokenException("无效秘钥:" + secretkey);
if(secretkey == null || secretkey.isEmpty() || secretkey.equals(SaSsoManager.getConfig().getSecretkey()) == false) {
throw new SaSsoException("无效秘钥:" + secretkey).setCode(SaSsoExceptionCode.CODE_20003);
}
}
@ -300,7 +301,7 @@ public class SaSsoTemplate {
*/
public String buildCheckTicketUrl(String ticket, String ssoLogoutCallUrl) {
// 裸地址
String url = SaManager.getConfig().getSso().getCheckTicketUrl();
String url = SaSsoManager.getConfig().getCheckTicketUrl();
// 拼接ticket参数
url = SaFoxUtil.joinParam(url, ParamName.ticket, ticket);
@ -340,7 +341,7 @@ public class SaSsoTemplate {
return;
}
String secretkey = SaManager.getConfig().getSso().getSecretkey();
String secretkey = SaSsoManager.getConfig().getSecretkey();
Set<String> urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, () -> new HashSet<String>());
for (String url : urlSet) {
// 拼接login参数秘钥参数
@ -357,7 +358,7 @@ public class SaSsoTemplate {
* @return 单点注销URL
*/
public String buildSloUrl(Object loginId) {
SaSsoConfig ssoConfig = SaManager.getConfig().getSso();
SaSsoConfig ssoConfig = SaSsoManager.getConfig();
String url = ssoConfig.getSloUrl();
url = SaFoxUtil.joinParam(url, ParamName.loginId, loginId);
url = SaFoxUtil.joinParam(url, ParamName.secretkey, ssoConfig.getSecretkey());
@ -389,7 +390,7 @@ public class SaSsoTemplate {
*/
public Object getUserinfo(Object loginId) {
String url = buildUserinfoUrl(loginId);
return SaManager.getConfig().getSso().getSendHttp().apply(url);
return SaSsoManager.getConfig().getSendHttp().apply(url);
}

View File

@ -0,0 +1,56 @@
package cn.dev33.satoken.sso.exception;
import cn.dev33.satoken.exception.SaTokenException;
/**
* 一个异常代表 SSO 认证流程错误
*
* @author kong
*/
public class SaSsoException extends SaTokenException {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 6806129545290130114L;
/**
* 一个异常代表 SSO 认证流程错误
* @param message 异常描述
*/
public SaSsoException(String message) {
super(message);
}
/**
* 一个异常代表 SSO 认证流程错误
* @param code 异常细分状态码
* @param message 异常描述
*/
public SaSsoException(int code, String message) {
super(code, message);
}
/**
* 写入异常细分状态码
* @param code 异常细分状态码
* @return 对象自身
*/
public SaSsoException setCode(int code) {
super.setCode(code);
return this;
}
/**
* 如果flag==true则抛出message异常
* @param flag 标记
* @param message 异常信息
*/
public static void throwBy(boolean flag, String message) {
if(flag) {
throw new SaSsoException(message);
}
}
}

View File

@ -0,0 +1,25 @@
package cn.dev33.satoken.sso.exception;
/**
* 定义所有 SSO 异常细分状态码
*
* @author kong
* @date: 2022-4-25
*/
public class SaSsoExceptionCode {
/** redirect 重定向 url 是一个无效地址 */
public static final int CODE_20001 = 20001;
/** redirect 重定向 url 不在 allowUrl 允许的范围内 */
public static final int CODE_20002 = 20002;
/** 接口调用方提供的 secretkey 秘钥无效 */
public static final int CODE_20003 = 20003;
/** 提供的 ticket 是无效的 */
public static final int CODE_20004 = 20004;
}

View File

@ -51,6 +51,13 @@
<version>${revision}</version>
<optional>true</optional>
</dependency>
<!-- SSO (optional) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>${revision}</version>
<optional>true</optional>
</dependency>
<!-- config -->
<dependency>

View File

@ -14,8 +14,6 @@ import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.id.SaIdTemplate;
import cn.dev33.satoken.id.SaIdUtil;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.sso.SaSsoTemplate;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
@ -119,16 +117,6 @@ public class SaBeanInject {
SaBasicUtil.saBasicTemplate = saBasicTemplate;
}
/**
* 注入 Sa-Token-SSO 单点登录模块 Bean
*
* @param saSsoTemplate saSsoTemplate对象
*/
@Autowired(required = false)
public void setSaSsoTemplate(SaSsoTemplate saSsoTemplate) {
SaSsoUtil.saSsoTemplate = saSsoTemplate;
}
/**
* 注入自定义的 StpLogic
* @param stpLogic /

View File

@ -0,0 +1,40 @@
package cn.dev33.satoken.reactor.spring.sso;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.sso.SaSsoManager;
import cn.dev33.satoken.sso.SaSsoTemplate;
import cn.dev33.satoken.sso.SaSsoUtil;
/**
* 注入 Sa-Token-SSO 所需要的Bean
*
* @author kong
*
*/
@ConditionalOnClass(SaSsoManager.class)
public class SaSsoBeanInject {
/**
* 注入 Sa-Token-SSO 配置Bean
*
* @param saSsoConfig 配置对象
*/
@Autowired(required = false)
public void setSaOAuth2Config(SaSsoConfig saSsoConfig) {
SaSsoManager.setConfig(saSsoConfig);
}
/**
* 注入 Sa-Token-SSO 单点登录模块 Bean
*
* @param saSsoTemplate saSsoTemplate对象
*/
@Autowired(required = false)
public void setSaSsoTemplate(SaSsoTemplate saSsoTemplate) {
SaSsoUtil.saSsoTemplate = saSsoTemplate;
}
}

View File

@ -0,0 +1,28 @@
package cn.dev33.satoken.reactor.spring.sso;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.sso.SaSsoManager;
/**
* 注册 Sa-Token-SSO 所需要的Bean
* @author kong
*
*/
@ConditionalOnClass(SaSsoManager.class)
public class SaSsoBeanRegister {
/**
* 获取 SSO 配置Bean
* @return 配置对象
*/
@Bean
@ConfigurationProperties(prefix = "sa-token.sso")
public SaSsoConfig getSaSsoConfig() {
return new SaSsoConfig();
}
}

View File

@ -0,0 +1,4 @@
/**
* Sa-Token-SSO 模块自动化配置只有引入了 sa-token-sso 模块后此包下的代码才会开始工作
*/
package cn.dev33.satoken.reactor.spring.sso;

View File

@ -1,5 +1,7 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.dev33.satoken.reactor.spring.SaBeanRegister,\
cn.dev33.satoken.reactor.spring.SaBeanInject,\
cn.dev33.satoken.reactor.spring.sso.SaSsoBeanRegister,\
cn.dev33.satoken.reactor.spring.sso.SaSsoBeanInject,\
cn.dev33.satoken.reactor.spring.oauth2.SaOAuth2BeanRegister,\
cn.dev33.satoken.reactor.spring.oauth2.SaOAuth2BeanInject

View File

@ -21,8 +21,6 @@ import cn.dev33.satoken.id.SaIdUtil;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.solon.integration.SaContextForSolon;
import cn.dev33.satoken.solon.integration.SaTokenMethodInterceptor;
import cn.dev33.satoken.sso.SaSsoTemplate;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
@ -92,11 +90,6 @@ public class XPluginImp implements Plugin {
SaBasicUtil.saBasicTemplate = bw.raw();
});
// Sa-Token-SSO 单点登录模块 Bean
Aop.getAsyn(SaSsoTemplate.class, bw->{
SaSsoUtil.saSsoTemplate = bw.raw();
});
// 自定义 StpLogic 对象
Aop.getAsyn(StpLogic.class, bw->{
StpUtil.setStpLogic(bw.raw());

View File

@ -34,6 +34,14 @@
<version>${revision}</version>
<optional>true</optional>
</dependency>
<!-- SSO (optional) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>${revision}</version>
<optional>true</optional>
</dependency>
<!-- config -->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -0,0 +1,40 @@
package cn.dev33.satoken.spring.sso;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.sso.SaSsoManager;
import cn.dev33.satoken.sso.SaSsoTemplate;
import cn.dev33.satoken.sso.SaSsoUtil;
/**
* 注入 Sa-Token-SSO 所需要的Bean
*
* @author kong
*
*/
@ConditionalOnClass(SaSsoManager.class)
public class SaSsoBeanInject {
/**
* 注入 Sa-Token-SSO 配置Bean
*
* @param saSsoConfig 配置对象
*/
@Autowired(required = false)
public void setSaOAuth2Config(SaSsoConfig saSsoConfig) {
SaSsoManager.setConfig(saSsoConfig);
}
/**
* 注入 Sa-Token-SSO 单点登录模块 Bean
*
* @param saSsoTemplate saSsoTemplate对象
*/
@Autowired(required = false)
public void setSaSsoTemplate(SaSsoTemplate saSsoTemplate) {
SaSsoUtil.saSsoTemplate = saSsoTemplate;
}
}

View File

@ -0,0 +1,28 @@
package cn.dev33.satoken.spring.sso;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.sso.SaSsoManager;
/**
* 注册 Sa-Token-SSO 所需要的Bean
* @author kong
*
*/
@ConditionalOnClass(SaSsoManager.class)
public class SaSsoBeanRegister {
/**
* 获取 SSO 配置Bean
* @return 配置对象
*/
@Bean
@ConfigurationProperties(prefix = "sa-token.sso")
public SaSsoConfig getSaSsoConfig() {
return new SaSsoConfig();
}
}

View File

@ -0,0 +1,4 @@
/**
* Sa-Token-SSO 模块自动化配置只有引入了 sa-token-sso 模块后此包下的代码才会开始工作
*/
package cn.dev33.satoken.spring.sso;

View File

@ -1,5 +1,7 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.dev33.satoken.spring.SaBeanRegister,\
cn.dev33.satoken.spring.SaBeanInject,\
cn.dev33.satoken.spring.sso.SaSsoBeanRegister,\
cn.dev33.satoken.spring.sso.SaSsoBeanInject,\
cn.dev33.satoken.spring.oauth2.SaOAuth2BeanRegister,\
cn.dev33.satoken.spring.oauth2.SaOAuth2BeanInject