【功能优化】全局:LoginUser 新增过期时间,方便判断 token 过期

pull/126/MERGE
YunaiV 2024-07-20 18:42:26 +08:00
parent b728e66282
commit b0c2f75a3f
12 changed files with 80 additions and 12 deletions

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.jackson.core.databind; package cn.iocoder.yudao.framework.common.util.json.databind;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.SerializerProvider;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.jackson.core.databind; package cn.iocoder.yudao.framework.common.util.json.databind;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.jackson.core.databind; package cn.iocoder.yudao.framework.common.util.json.databind;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.JsonSerializer;

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -42,6 +43,10 @@ public class LoginUser {
* *
*/ */
private List<String> scopes; private List<String> scopes;
/**
*
*/
private LocalDateTime expiresTime;
// ========== 上下文 ========== // ========== 上下文 ==========
/** /**

View File

@ -96,7 +96,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
// 构建登录用户 // 构建登录用户
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType()) return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
.setInfo(accessToken.getUserInfo()) // 额外的用户信息 .setInfo(accessToken.getUserInfo()) // 额外的用户信息
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes()); .setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes())
.setExpiresTime(accessToken.getExpiresTime());
} catch (ServiceException serviceException) { } catch (ServiceException serviceException) {
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可 // 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
return null; return null;

View File

@ -2,9 +2,9 @@ package cn.iocoder.yudao.framework.jackson.config;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.jackson.core.databind.NumberSerializer; import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer;
import cn.iocoder.yudao.framework.jackson.core.databind.TimestampLocalDateTimeDeserializer; import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.jackson.core.databind.TimestampLocalDateTimeSerializer; import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.gateway.filter.security;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -35,5 +36,9 @@ public class LoginUser {
* *
*/ */
private List<String> scopes; private List<String> scopes;
/**
*
*/
private LocalDateTime expiresTime;
} }

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.gateway.filter.security;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.gateway.util.SecurityFrameworkUtils; import cn.iocoder.yudao.gateway.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.gateway.util.WebFrameworkUtils; import cn.iocoder.yudao.gateway.util.WebFrameworkUtils;
@ -94,7 +95,8 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered {
// 重要说明defaultIfEmpty 作用,保证 Mono.empty() 情况,可以继续执行 `flatMap 的 chain.filter(exchange)` 逻辑,避免返回给前端空的 Response // 重要说明defaultIfEmpty 作用,保证 Mono.empty() 情况,可以继续执行 `flatMap 的 chain.filter(exchange)` 逻辑,避免返回给前端空的 Response
return getLoginUser(exchange, token).defaultIfEmpty(LOGIN_USER_EMPTY).flatMap(user -> { return getLoginUser(exchange, token).defaultIfEmpty(LOGIN_USER_EMPTY).flatMap(user -> {
// 1. 无用户,直接 filter 继续请求 // 1. 无用户,直接 filter 继续请求
if (user == LOGIN_USER_EMPTY) { if (user == LOGIN_USER_EMPTY || // 下面 expiresTime 的判断,为了解决 token 实际已经过期的情况
user.getExpiresTime() == null || LocalDateTimeUtils.afterNow(user.getExpiresTime())) {
return chain.filter(exchange); return chain.filter(exchange);
} }
@ -153,7 +155,8 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered {
OAuth2AccessTokenCheckRespDTO tokenInfo = result.getData(); OAuth2AccessTokenCheckRespDTO tokenInfo = result.getData();
return new LoginUser().setId(tokenInfo.getUserId()).setUserType(tokenInfo.getUserType()) return new LoginUser().setId(tokenInfo.getUserId()).setUserType(tokenInfo.getUserType())
.setInfo(tokenInfo.getUserInfo()) // 额外的用户信息 .setInfo(tokenInfo.getUserInfo()) // 额外的用户信息
.setTenantId(tokenInfo.getTenantId()).setScopes(tokenInfo.getScopes()); .setTenantId(tokenInfo.getTenantId()).setScopes(tokenInfo.getScopes())
.setExpiresTime(tokenInfo.getExpiresTime());
} }
@Override @Override

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.gateway.jackson;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
@Configuration
@Slf4j
public class JacksonAutoConfiguration {
@Bean
public JsonUtils jsonUtils(List<ObjectMapper> objectMappers) {
// 1.1 创建 SimpleModule 对象
SimpleModule simpleModule = new SimpleModule();
simpleModule
// 新增 Long 类型序列化规则,数值超过 2^53-1在 JS 会出现精度丢失问题,因此 Long 自动序列化为字符串类型
.addSerializer(Long.class, NumberSerializer.INSTANCE)
.addSerializer(Long.TYPE, NumberSerializer.INSTANCE)
.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE)
.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE)
.addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE)
.addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE)
// 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
// 1.2 注册到 objectMapper
objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule));
// 2. 设置 objectMapper 到 JsonUtils
JsonUtils.init(CollUtil.getFirst(objectMappers));
log.info("[init][初始化 JsonUtils 成功]");
return new JsonUtils();
}
}

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum; import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -20,7 +20,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
public class CombinationRecordReqPageVO extends PageParam { public class CombinationRecordReqPageVO extends PageParam {
@Schema(description = "活动状态", example = "1") @Schema(description = "活动状态", example = "1")
@InEnum(BargainRecordStatusEnum.class) @InEnum(CombinationRecordStatusEnum.class)
private Integer status; private Integer status;
@Schema(description = "团长编号", example = "1024") @Schema(description = "团长编号", example = "1024")

View File

@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -26,4 +27,7 @@ public class OAuth2AccessTokenCheckRespDTO implements Serializable {
@Schema(description = "授权范围的数组", example = "user_info") @Schema(description = "授权范围的数组", example = "user_info")
private List<String> scopes; private List<String> scopes;
@Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime expiresTime;
} }

View File

@ -23,7 +23,6 @@ public class OAuth2TokenApiImpl implements OAuth2TokenApi {
private OAuth2TokenService oauth2TokenService; private OAuth2TokenService oauth2TokenService;
@Override @Override
@Operation(description = "创建访问令牌")
public CommonResult<OAuth2AccessTokenRespDTO> createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) { public CommonResult<OAuth2AccessTokenRespDTO> createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken( OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(
reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes()); reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes());