From cd7374b3e9b881e72754dbc7e96e67ef422b8af1 Mon Sep 17 00:00:00 2001 From: fengshuonan Date: Tue, 7 Nov 2023 14:04:14 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=908.0.2=E3=80=91=E3=80=90auth=E3=80=91?= =?UTF-8?q?=E6=9B=B4=E6=96=B0Token=E7=99=BB=E5=BD=95=E4=B8=9A=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roses/kernel/auth/api/AuthServiceApi.java | 4 +- .../auth/api/pojo/sso/DecryptCaLoginUser.java | 46 ++++++++++++ .../auth/api/pojo/sso/DecryptCaTokenInfo.java | 33 +++++++++ .../LoginBySsoTokenRequest.java} | 4 +- .../kernel/auth/auth/AuthServiceImpl.java | 70 ++++++++----------- 5 files changed, 114 insertions(+), 43 deletions(-) create mode 100644 kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/sso/DecryptCaLoginUser.java create mode 100644 kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/sso/DecryptCaTokenInfo.java rename kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/{auth/LoginWithTokenRequest.java => sso/LoginBySsoTokenRequest.java} (79%) 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 6b9d0e935..f669b30e0 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,9 +27,9 @@ 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; import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser; import cn.stylefeng.roses.kernel.auth.api.pojo.payload.DefaultJwtPayload; +import cn.stylefeng.roses.kernel.auth.api.pojo.sso.LoginBySsoTokenRequest; /** * 认证服务的接口,包括基本的登录退出操作和校验token等操作 @@ -75,7 +75,7 @@ public interface AuthServiceApi { * @author fengshuonan * @since 2021/5/25 22:44 */ - LoginResponse LoginWithToken(LoginWithTokenRequest loginWithTokenRequest); + LoginResponse LoginByCaToken(LoginBySsoTokenRequest loginWithTokenRequest); /** * 当前登录人退出登录 diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/sso/DecryptCaLoginUser.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/sso/DecryptCaLoginUser.java new file mode 100644 index 000000000..d2aac0f07 --- /dev/null +++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/sso/DecryptCaLoginUser.java @@ -0,0 +1,46 @@ +package cn.stylefeng.roses.kernel.auth.api.pojo.sso; + +import lombok.Data; + +import java.util.Map; + +/** + * 统一认证中心登录用户信息 + * + * @author fengshuonan + * @date 2021/1/21 14:04 + */ +@Data +public class DecryptCaLoginUser { + + /** + * 统一认证中心的会话的token + */ + private String caToken; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 用户账号id + */ + private Long userId; + + /** + * 账号 + */ + private String account; + + /** + * 真实姓名 + */ + private String realName; + + /** + * 其他属性 + */ + private Map otherProperties; + +} diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/sso/DecryptCaTokenInfo.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/sso/DecryptCaTokenInfo.java new file mode 100644 index 000000000..69f2f45da --- /dev/null +++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/sso/DecryptCaTokenInfo.java @@ -0,0 +1,33 @@ +package cn.stylefeng.roses.kernel.auth.api.pojo.sso; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * 生成SSO token时候的格式 + * + * @author fengshuonan + * @since 2023/11/5 12:31 + */ +@Data +@AllArgsConstructor +public class DecryptCaTokenInfo { + + /** + * 统一认证中心中,用户的token + */ + private String caToken; + + /** + * 用户id + */ + private DecryptCaLoginUser caLoginUser; + + /** + * 生成token时的时间 + *

+ * 格式是:yyyyMMddHHmmss + */ + private String generationDateTime; + +} 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/sso/LoginBySsoTokenRequest.java similarity index 79% rename from kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/auth/LoginWithTokenRequest.java rename to kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/pojo/sso/LoginBySsoTokenRequest.java index a83d55f35..42b425190 100644 --- 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/sso/LoginBySsoTokenRequest.java @@ -1,4 +1,4 @@ -package cn.stylefeng.roses.kernel.auth.api.pojo.auth; +package cn.stylefeng.roses.kernel.auth.api.pojo.sso; import cn.stylefeng.roses.kernel.rule.pojo.request.BaseRequest; import lombok.Data; @@ -14,7 +14,7 @@ import javax.validation.constraints.NotBlank; */ @EqualsAndHashCode(callSuper = true) @Data -public class LoginWithTokenRequest extends BaseRequest { +public class LoginBySsoTokenRequest extends BaseRequest { /** * 从单点服务获取到的token diff --git a/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/AuthServiceImpl.java b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/AuthServiceImpl.java index 3db79b46d..845b159be 100644 --- a/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/AuthServiceImpl.java +++ b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/AuthServiceImpl.java @@ -25,6 +25,9 @@ package cn.stylefeng.roses.kernel.auth.auth; import cn.hutool.core.codec.Base64; +import cn.hutool.core.date.DateField; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; @@ -39,25 +42,24 @@ import cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum; import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander; 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.auth.api.pojo.payload.DefaultJwtPayload; +import cn.stylefeng.roses.kernel.auth.api.pojo.sso.DecryptCaLoginUser; +import cn.stylefeng.roses.kernel.auth.api.pojo.sso.DecryptCaTokenInfo; +import cn.stylefeng.roses.kernel.auth.api.pojo.sso.LoginBySsoTokenRequest; import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi; import cn.stylefeng.roses.kernel.demo.expander.DemoConfigExpander; -import cn.stylefeng.roses.kernel.jwt.JwtTokenOperator; import cn.stylefeng.roses.kernel.jwt.api.JwtApi; import cn.stylefeng.roses.kernel.jwt.api.exception.JwtException; import cn.stylefeng.roses.kernel.jwt.api.exception.enums.JwtExceptionEnum; -import cn.stylefeng.roses.kernel.jwt.api.pojo.config.JwtConfig; import cn.stylefeng.roses.kernel.log.api.LoginLogServiceApi; import cn.stylefeng.roses.kernel.sys.api.SysUserServiceApi; import cn.stylefeng.roses.kernel.sys.api.pojo.user.UserValidateDTO; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import io.jsonwebtoken.Claims; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.util.Date; import static cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum.AUTH_EXPIRED_ERROR; import static cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum.TOKEN_PARSE_ERROR; @@ -112,52 +114,42 @@ public class AuthServiceImpl implements AuthServiceApi { } @Override - public LoginResponse LoginWithToken(LoginWithTokenRequest loginWithTokenRequest) { + public LoginResponse LoginByCaToken(LoginBySsoTokenRequest loginWithTokenRequest) { - // 解析jwt token中的账号 - JwtConfig jwtConfig = new JwtConfig(); - jwtConfig.setJwtSecret(AuthConfigExpander.getSsoJwtSecret()); - jwtConfig.setExpiredSeconds(0L); + // sso token是一个加密的字符串,需要用AES秘钥对称解密 + String encryptUserInfo = loginWithTokenRequest.getToken(); - // jwt工具类初始化 - JwtTokenOperator jwtTokenOperator = new JwtTokenOperator(jwtConfig); + // aes解密出用户信息 + AES aesUtil = SecureUtil.aes(Base64.decode(AuthConfigExpander.getSsoDataDecryptSecret())); + String userInfoJson = aesUtil.decryptStr(encryptUserInfo, CharsetUtil.CHARSET_UTF_8); - // 解析token中的用户信息 - Claims payload = null; - try { - payload = jwtTokenOperator.getJwtPayloadClaims(loginWithTokenRequest.getToken()); - } catch (Exception exception) { - throw new AuthException(AuthExceptionEnum.SSO_TOKEN_PARSE_ERROR, exception.getMessage()); + // 转化为实体类 + DecryptCaTokenInfo decryptCaTokenInfo = JSON.parseObject(userInfoJson, DecryptCaTokenInfo.class); + + // 如果时间大于2分钟则认定token过期 + String tokenGenerateTimeStr = decryptCaTokenInfo.getGenerationDateTime(); + DateTime tokenGenerateTime = DateUtil.parse(tokenGenerateTimeStr); + DateTime tokenExpTime = tokenGenerateTime.offset(DateField.MINUTE, 2); + if (tokenExpTime.isBefore(new Date())) { + throw new AuthException(AuthExceptionEnum.SSO_TOKEN_PARSE_ERROR, "sso token过期"); } - // 获取到用户信息 - Object userInfoEncryptString = payload.get("userInfo"); - if (ObjectUtil.isEmpty(userInfoEncryptString)) { + // 获取token中的用户信息 + DecryptCaLoginUser caLoginUser = decryptCaTokenInfo.getCaLoginUser(); + if (caLoginUser == null) { throw new AuthException(AuthExceptionEnum.SSO_TOKEN_GET_USER_ERROR); } // 解密出用户账号和caToken(caToken用于校验用户是否在单点中心) - String account = null; - String caToken = null; - try { - AES aesUtil = SecureUtil.aes(Base64.decode(AuthConfigExpander.getSsoDataDecryptSecret())); - String loginUserJson = aesUtil.decryptStr(userInfoEncryptString.toString(), CharsetUtil.CHARSET_UTF_8); - JSONObject userInfoJsonObject = JSON.parseObject(loginUserJson); - account = userInfoJsonObject.getString("account"); - caToken = userInfoJsonObject.getString("caToken"); - } catch (Exception exception) { - throw new AuthException(AuthExceptionEnum.SSO_TOKEN_DECRYPT_USER_ERROR, exception.getMessage()); + if (ObjectUtil.isEmpty(caLoginUser.getAccount()) || ObjectUtil.isEmpty(caLoginUser.getCaToken())) { + throw new AuthException(AuthExceptionEnum.SSO_TOKEN_GET_USER_ERROR); } - // 账号为空,抛出异常 - if (account == null) { - throw new AuthException(AuthExceptionEnum.SSO_TOKEN_DECRYPT_USER_ERROR); - } + // 通过账号和caToken登录 + LoginResponse loginResponse = loginWithUserNameAndCaToken(caLoginUser.getAccount(), caLoginUser.getCaToken()); - LoginResponse loginResponse = loginWithUserNameAndCaToken(account, caToken); - - // 存储单点token和生成的本地token的映射关系 - caClientTokenCacheApi.put(loginWithTokenRequest.getToken(), loginResponse.getToken()); + // 存储单点token和生成的本地token的映射关系,用在远程退出的时,将本地缓存清空 + caClientTokenCacheApi.put(caLoginUser.getCaToken(), loginResponse.getToken()); return loginResponse; }