mirror of https://gitee.com/stylefeng/roses
【8.0.2】【auth】更新Token登录业务
parent
34ec18bef5
commit
cd7374b3e9
|
@ -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.exception.AuthException;
|
||||||
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
|
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.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.login.LoginUser;
|
||||||
import cn.stylefeng.roses.kernel.auth.api.pojo.payload.DefaultJwtPayload;
|
import cn.stylefeng.roses.kernel.auth.api.pojo.payload.DefaultJwtPayload;
|
||||||
|
import cn.stylefeng.roses.kernel.auth.api.pojo.sso.LoginBySsoTokenRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证服务的接口,包括基本的登录退出操作和校验token等操作
|
* 认证服务的接口,包括基本的登录退出操作和校验token等操作
|
||||||
|
@ -75,7 +75,7 @@ public interface AuthServiceApi {
|
||||||
* @author fengshuonan
|
* @author fengshuonan
|
||||||
* @since 2021/5/25 22:44
|
* @since 2021/5/25 22:44
|
||||||
*/
|
*/
|
||||||
LoginResponse LoginWithToken(LoginWithTokenRequest loginWithTokenRequest);
|
LoginResponse LoginByCaToken(LoginBySsoTokenRequest loginWithTokenRequest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前登录人退出登录
|
* 当前登录人退出登录
|
||||||
|
|
|
@ -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<String, Object> otherProperties;
|
||||||
|
|
||||||
|
}
|
|
@ -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时的时间
|
||||||
|
* <p>
|
||||||
|
* 格式是:yyyyMMddHHmmss
|
||||||
|
*/
|
||||||
|
private String generationDateTime;
|
||||||
|
|
||||||
|
}
|
|
@ -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 cn.stylefeng.roses.kernel.rule.pojo.request.BaseRequest;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -14,7 +14,7 @@ import javax.validation.constraints.NotBlank;
|
||||||
*/
|
*/
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
public class LoginWithTokenRequest extends BaseRequest {
|
public class LoginBySsoTokenRequest extends BaseRequest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从单点服务获取到的token
|
* 从单点服务获取到的token
|
|
@ -25,6 +25,9 @@
|
||||||
package cn.stylefeng.roses.kernel.auth.auth;
|
package cn.stylefeng.roses.kernel.auth.auth;
|
||||||
|
|
||||||
import cn.hutool.core.codec.Base64;
|
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.CharsetUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
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.expander.AuthConfigExpander;
|
||||||
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
|
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.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.login.LoginUser;
|
||||||
import cn.stylefeng.roses.kernel.auth.api.pojo.payload.DefaultJwtPayload;
|
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.cache.api.CacheOperatorApi;
|
||||||
import cn.stylefeng.roses.kernel.demo.expander.DemoConfigExpander;
|
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.JwtApi;
|
||||||
import cn.stylefeng.roses.kernel.jwt.api.exception.JwtException;
|
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.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.log.api.LoginLogServiceApi;
|
||||||
import cn.stylefeng.roses.kernel.sys.api.SysUserServiceApi;
|
import cn.stylefeng.roses.kernel.sys.api.SysUserServiceApi;
|
||||||
import cn.stylefeng.roses.kernel.sys.api.pojo.user.UserValidateDTO;
|
import cn.stylefeng.roses.kernel.sys.api.pojo.user.UserValidateDTO;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
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.AUTH_EXPIRED_ERROR;
|
||||||
import static cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum.TOKEN_PARSE_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
|
@Override
|
||||||
public LoginResponse LoginWithToken(LoginWithTokenRequest loginWithTokenRequest) {
|
public LoginResponse LoginByCaToken(LoginBySsoTokenRequest loginWithTokenRequest) {
|
||||||
|
|
||||||
// 解析jwt token中的账号
|
// sso token是一个加密的字符串,需要用AES秘钥对称解密
|
||||||
JwtConfig jwtConfig = new JwtConfig();
|
String encryptUserInfo = loginWithTokenRequest.getToken();
|
||||||
jwtConfig.setJwtSecret(AuthConfigExpander.getSsoJwtSecret());
|
|
||||||
jwtConfig.setExpiredSeconds(0L);
|
|
||||||
|
|
||||||
// jwt工具类初始化
|
// aes解密出用户信息
|
||||||
JwtTokenOperator jwtTokenOperator = new JwtTokenOperator(jwtConfig);
|
AES aesUtil = SecureUtil.aes(Base64.decode(AuthConfigExpander.getSsoDataDecryptSecret()));
|
||||||
|
String userInfoJson = aesUtil.decryptStr(encryptUserInfo, CharsetUtil.CHARSET_UTF_8);
|
||||||
|
|
||||||
// 解析token中的用户信息
|
// 转化为实体类
|
||||||
Claims payload = null;
|
DecryptCaTokenInfo decryptCaTokenInfo = JSON.parseObject(userInfoJson, DecryptCaTokenInfo.class);
|
||||||
try {
|
|
||||||
payload = jwtTokenOperator.getJwtPayloadClaims(loginWithTokenRequest.getToken());
|
// 如果时间大于2分钟则认定token过期
|
||||||
} catch (Exception exception) {
|
String tokenGenerateTimeStr = decryptCaTokenInfo.getGenerationDateTime();
|
||||||
throw new AuthException(AuthExceptionEnum.SSO_TOKEN_PARSE_ERROR, exception.getMessage());
|
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过期");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取到用户信息
|
// 获取token中的用户信息
|
||||||
Object userInfoEncryptString = payload.get("userInfo");
|
DecryptCaLoginUser caLoginUser = decryptCaTokenInfo.getCaLoginUser();
|
||||||
if (ObjectUtil.isEmpty(userInfoEncryptString)) {
|
if (caLoginUser == null) {
|
||||||
throw new AuthException(AuthExceptionEnum.SSO_TOKEN_GET_USER_ERROR);
|
throw new AuthException(AuthExceptionEnum.SSO_TOKEN_GET_USER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解密出用户账号和caToken(caToken用于校验用户是否在单点中心)
|
// 解密出用户账号和caToken(caToken用于校验用户是否在单点中心)
|
||||||
String account = null;
|
if (ObjectUtil.isEmpty(caLoginUser.getAccount()) || ObjectUtil.isEmpty(caLoginUser.getCaToken())) {
|
||||||
String caToken = null;
|
throw new AuthException(AuthExceptionEnum.SSO_TOKEN_GET_USER_ERROR);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 账号为空,抛出异常
|
// 通过账号和caToken登录
|
||||||
if (account == null) {
|
LoginResponse loginResponse = loginWithUserNameAndCaToken(caLoginUser.getAccount(), caLoginUser.getCaToken());
|
||||||
throw new AuthException(AuthExceptionEnum.SSO_TOKEN_DECRYPT_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoginResponse loginResponse = loginWithUserNameAndCaToken(account, caToken);
|
// 存储单点token和生成的本地token的映射关系,用在远程退出的时,将本地缓存清空
|
||||||
|
caClientTokenCacheApi.put(caLoginUser.getCaToken(), loginResponse.getToken());
|
||||||
// 存储单点token和生成的本地token的映射关系
|
|
||||||
caClientTokenCacheApi.put(loginWithTokenRequest.getToken(), loginResponse.getToken());
|
|
||||||
|
|
||||||
return loginResponse;
|
return loginResponse;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue