diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/AuthServiceApi.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/AuthServiceApi.java
index e637d9b30..b6cdb7329 100644
--- a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/AuthServiceApi.java
+++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/AuthServiceApi.java
@@ -27,6 +27,7 @@ package cn.stylefeng.roses.kernel.auth.api;
import cn.stylefeng.roses.kernel.auth.api.exception.AuthException;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse;
+import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginWithTokenRequest;
/**
* 认证服务的接口,包括基本的登录退出操作和校验token等操作
@@ -55,6 +56,25 @@ public interface AuthServiceApi {
*/
LoginResponse loginWithUserName(String username);
+ /**
+ * 登录(通过账号和sso后的token),一般用在单点登录
+ *
+ * @param username 账号
+ * @param caToken sso登录成功后的会话
+ * @author fengshuonan
+ * @date 2021/5/25 22:44
+ */
+ LoginResponse loginWithUserNameAndCaToken(String username, String caToken);
+
+ /**
+ * 通过token进行登录,一般用在单点登录服务
+ *
+ * @param loginWithTokenRequest 请求
+ * @author fengshuonan
+ * @date 2021/5/25 22:44
+ */
+ LoginResponse LoginWithToken(LoginWithTokenRequest loginWithTokenRequest);
+
/**
* 当前登录人退出登录
*
diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/constants/AuthConstants.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/constants/AuthConstants.java
index 470791f6b..0570412d5 100644
--- a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/constants/AuthConstants.java
+++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/constants/AuthConstants.java
@@ -77,4 +77,49 @@ public interface AuthConstants {
*/
String KAPTCHA_SESSION_KEY = "KAPTCHA_SESSION_KEY";
+ /**
+ * 默认解析jwt的秘钥(用于解析sso传过来的token)
+ */
+ String SYS_AUTH_SSO_JWT_SECRET = "aabbccdd";
+
+ /**
+ * 默认解密sso单点中jwt中payload的秘钥
+ */
+ String SYS_AUTH_SSO_DECRYPT_DATA_SECRET = "EDPpR/BQfEFJiXKgxN8Uno4OnNMGcIJW1F777yySCPA=";
+
+ /**
+ * 是否开启sso远程会话校验
+ */
+ Boolean SYS_AUTH_SSO_SESSION_VALIDATE_SWITCH = false;
+
+ /**
+ * 用于远程session校验redis的host
+ */
+ String SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_HOST = "localhost";
+
+ /**
+ * 用于远程session校验redis的端口
+ */
+ Integer SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_PORT = 6379;
+
+ /**
+ * 用于远程session校验redis的数据库index
+ */
+ Integer SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_DB_INDEX = 2;
+
+ /**
+ * 用于远程session校验redis的缓存前缀
+ */
+ String SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_CACHE_PREFIX = "CA:USER:TOKEN:";
+
+ /**
+ * SSO的默认地址
+ */
+ String SYS_AUTH_SSO_HOST = "http://localhost:8888";
+
+ /**
+ * sso获取loginCode的url
+ */
+ String SYS_AUTH_SSO_GET_LOGIN_CODE = "/sso/getLoginCode";
+
}
diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/exception/enums/AuthExceptionEnum.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/exception/enums/AuthExceptionEnum.java
index 949f12098..6e4a15aba 100644
--- a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/exception/enums/AuthExceptionEnum.java
+++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/exception/enums/AuthExceptionEnum.java
@@ -96,7 +96,27 @@ public enum AuthExceptionEnum implements AbstractExceptionEnum {
/**
* 用户角色未绑定,登录失败
*/
- ROLE_IS_EMPTY(RuleConstants.BUSINESS_ERROR_TYPE_CODE + AuthConstants.AUTH_EXCEPTION_STEP_CODE + "12", "用户角色未绑定,登录失败");
+ ROLE_IS_EMPTY(RuleConstants.BUSINESS_ERROR_TYPE_CODE + AuthConstants.AUTH_EXCEPTION_STEP_CODE + "12", "用户角色未绑定,登录失败"),
+
+ /**
+ * SSO登录获取loginCode失败
+ */
+ SSO_LOGIN_CODE_GET_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + AuthConstants.AUTH_EXCEPTION_STEP_CODE + "13", "登录失败,具体信息为:{}"),
+
+ /**
+ * SSO使用token登录时,token解析异常
+ */
+ SSO_TOKEN_PARSE_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + AuthConstants.AUTH_EXCEPTION_STEP_CODE + "14", "token解析异常:{}"),
+
+ /**
+ * SSO使用token登录时,解析token中的用户信息错误,用户信息为空
+ */
+ SSO_TOKEN_GET_USER_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + AuthConstants.AUTH_EXCEPTION_STEP_CODE + "15", "解析token中的用户信息错误,用户信息为空"),
+
+ /**
+ * SSO使用token登录时,解密token出错
+ */
+ SSO_TOKEN_DECRYPT_USER_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + AuthConstants.AUTH_EXCEPTION_STEP_CODE + "16", "解密token出错:{}");
/**
* 错误编码
diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/expander/AuthConfigExpander.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/expander/AuthConfigExpander.java
index 25c8c4d19..49e333d00 100644
--- a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/expander/AuthConfigExpander.java
+++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/expander/AuthConfigExpander.java
@@ -144,4 +144,95 @@ public class AuthConfigExpander {
return ConfigContext.me().getSysConfigValueWithDefault("SYS_SESSION_COOKIE_NAME", String.class, DEFAULT_AUTH_HEADER_NAME);
}
+ /**
+ * 默认解析jwt的秘钥(用于解析sso传过来的token)
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:39
+ */
+ public static String getSsoJwtSecret() {
+ return ConfigContext.me().getSysConfigValueWithDefault("SYS_AUTH_SSO_JWT_SECRET", String.class, SYS_AUTH_SSO_JWT_SECRET);
+ }
+
+ /**
+ * 默认解析sso加密的数据的秘钥
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:39
+ */
+ public static String getSsoDataDecryptSecret() {
+ return ConfigContext.me().getSysConfigValueWithDefault("SYS_AUTH_SSO_DECRYPT_DATA_SECRET", String.class, SYS_AUTH_SSO_DECRYPT_DATA_SECRET);
+ }
+
+ /**
+ * 获取是否开启sso远程会话校验,当系统对接sso后,如需同时校验sso的会话是否存在则开启此开关
+ *
+ * @return true-开启远程校验,false-关闭远程校验
+ * @author fengshuonan
+ * @date 2021/5/25 22:39
+ */
+ public static Boolean getSsoSessionValidateSwitch() {
+ return ConfigContext.me().getSysConfigValueWithDefault("SYS_AUTH_SSO_SESSION_VALIDATE_SWITCH", Boolean.class, SYS_AUTH_SSO_SESSION_VALIDATE_SWITCH);
+ }
+
+ /**
+ * sso会话远程校验,redis的host
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:39
+ */
+ public static String getSsoSessionValidateRedisHost() {
+ return ConfigContext.me().getSysConfigValueWithDefault("SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_HOST", String.class, SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_HOST);
+ }
+
+ /**
+ * sso会话远程校验,redis的端口
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:39
+ */
+ public static Integer getSsoSessionValidateRedisPort() {
+ return ConfigContext.me().getSysConfigValueWithDefault("SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_PORT", Integer.class, SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_PORT);
+ }
+
+ /**
+ * sso会话远程校验,redis的密码
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:39
+ */
+ public static String getSsoSessionValidateRedisPassword() {
+ return ConfigContext.me().getConfigValueNullable("SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_PASSWORD", String.class);
+ }
+
+ /**
+ * sso会话远程校验,redis的db
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:39
+ */
+ public static Integer getSsoSessionValidateRedisDbIndex() {
+ return ConfigContext.me().getSysConfigValueWithDefault("SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_DB_INDEX", Integer.class, SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_DB_INDEX);
+ }
+
+ /**
+ * sso会话远程校验,redis的缓存前缀
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:39
+ */
+ public static String getSsoSessionValidateRedisCachePrefix() {
+ return ConfigContext.me().getSysConfigValueWithDefault("SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_CACHE_PREFIX", String.class, SYS_AUTH_SSO_SESSION_VALIDATE_REDIS_CACHE_PREFIX);
+ }
+
+ /**
+ * 获取SSO服务器的地址
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:39
+ */
+ public static String getSsoUrl() {
+ return ConfigContext.me().getSysConfigValueWithDefault("SYS_AUTH_SSO_HOST", String.class, SYS_AUTH_SSO_HOST);
+ }
+
}
diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/SsoProperties.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/SsoProperties.java
new file mode 100644
index 000000000..3290e3309
--- /dev/null
+++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/SsoProperties.java
@@ -0,0 +1,19 @@
+package cn.stylefeng.roses.kernel.auth.api.pojo;
+
+import lombok.Data;
+
+/**
+ * SSO的配置
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:28
+ */
+@Data
+public class SsoProperties {
+
+ /**
+ * 是否开启,true-开启单点,false-关闭单点
+ */
+ private Boolean openFlag;
+
+}
diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/auth/LoginResponse.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/auth/LoginResponse.java
index 18f7742a6..633dde7ea 100644
--- a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/auth/LoginResponse.java
+++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/auth/LoginResponse.java
@@ -51,10 +51,37 @@ public class LoginResponse {
*/
private Long expireAt;
+ /**
+ * 使用单点登录
+ */
+ private Boolean ssoLogin;
+
+ /**
+ * 单点登录的loginCode
+ */
+ private String ssoLoginCode;
+
+ /**
+ * 用于普通登录的组装
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:31
+ */
public LoginResponse(LoginUser loginUser, String token, Long expireAt) {
this.loginUser = loginUser;
this.token = token;
this.expireAt = expireAt;
}
+ /**
+ * 用于单点登录,返回用户loginCode
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:31
+ */
+ public LoginResponse(String loginCode) {
+ this.ssoLogin = true;
+ this.ssoLoginCode = loginCode;
+ }
+
}
diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/auth/LoginWithTokenRequest.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/auth/LoginWithTokenRequest.java
new file mode 100644
index 000000000..b7f9d359a
--- /dev/null
+++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/auth/LoginWithTokenRequest.java
@@ -0,0 +1,25 @@
+package cn.stylefeng.roses.kernel.auth.api.pojo.auth;
+
+import cn.stylefeng.roses.kernel.rule.pojo.request.BaseRequest;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 单点获取到的token
+ *
+ * @author fengshuonan
+ * @date 2021/5/25 22:43
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class LoginWithTokenRequest extends BaseRequest {
+
+ /**
+ * 从单点服务获取到的token
+ */
+ @NotBlank(message = "token不能为空")
+ private String token;
+
+}
diff --git a/kernel-d-auth/auth-sdk/pom.xml b/kernel-d-auth/auth-sdk/pom.xml
index 8791cacb2..654f72335 100644
--- a/kernel-d-auth/auth-sdk/pom.xml
+++ b/kernel-d-auth/auth-sdk/pom.xml
@@ -68,7 +68,7 @@
+ * 用来校验单点中心是否有本用户的会话 + */ + private String caToken; + /** * 其他载体信息 */ @@ -71,11 +78,12 @@ public class DefaultJwtPayload { public DefaultJwtPayload() { } - public DefaultJwtPayload(Long userId, String account, boolean rememberMe) { + public DefaultJwtPayload(Long userId, String account, boolean rememberMe, String caToken) { this.userId = userId; this.account = account; this.uuid = IdUtil.fastUUID(); this.rememberMe = rememberMe; + this.caToken = caToken; } } diff --git a/kernel-s-system/system-business-user/src/main/java/cn/stylefeng/roses/kernel/system/modular/user/controller/LoginController.java b/kernel-s-system/system-business-user/src/main/java/cn/stylefeng/roses/kernel/system/modular/user/controller/LoginController.java index eb8d79de5..529539c8c 100644 --- a/kernel-s-system/system-business-user/src/main/java/cn/stylefeng/roses/kernel/system/modular/user/controller/LoginController.java +++ b/kernel-s-system/system-business-user/src/main/java/cn/stylefeng/roses/kernel/system/modular/user/controller/LoginController.java @@ -28,6 +28,7 @@ import cn.stylefeng.roses.kernel.auth.api.AuthServiceApi; import cn.stylefeng.roses.kernel.auth.api.context.LoginContext; import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest; import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse; +import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginWithTokenRequest; import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser; import cn.stylefeng.roses.kernel.rule.pojo.response.ResponseData; import cn.stylefeng.roses.kernel.rule.pojo.response.SuccessResponseData; @@ -84,6 +85,18 @@ public class LoginController { return new SuccessResponseData(loginResponse.getToken()); } + /** + * 基于token登录,适用于单点登录 + * + * @author fengshuonan + * @date 2021/5/25 22:36 + */ + @PostResource(name = "适用于单点登录", path = "/loginWithToken", requiredLogin = false, requiredPermission = false) + public ResponseData loginWithToken(@RequestBody @Validated LoginWithTokenRequest loginWithTokenRequest) { + LoginResponse loginResponse = authServiceApi.LoginWithToken(loginWithTokenRequest); + return new SuccessResponseData(loginResponse.getToken()); + } + /** * 用户登出 *