From 12b226fdc9ef370c5037d8315cc36351927df266 Mon Sep 17 00:00:00 2001 From: "Ray.Hao" <1490493387@qq.com> Date: Fri, 3 Jul 2026 18:22:48 +0800 Subject: [PATCH] =?UTF-8?q?fix(security):=20=E4=BF=AE=E5=A4=8DRedisTokenMa?= =?UTF-8?q?nager=E4=BC=9A=E8=AF=9D=E5=8F=8D=E5=BA=8F=E5=88=97=E5=8C=96?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E8=BD=AC=E6=8D=A2=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 提取JsonMapper为共享Bean,统一序列化配置 - 使用convertValue替代直接强转,正确处理嵌套泛型 --- .../boot/framework/cache/RedisConfig.java | 21 ++++++++++++++----- .../security/token/RedisTokenManager.java | 18 +++++++++++----- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/youlai/boot/framework/cache/RedisConfig.java b/src/main/java/com/youlai/boot/framework/cache/RedisConfig.java index da7eda28..610380d9 100644 --- a/src/main/java/com/youlai/boot/framework/cache/RedisConfig.java +++ b/src/main/java/com/youlai/boot/framework/cache/RedisConfig.java @@ -24,10 +24,12 @@ public class RedisConfig { * 修改 Redis 序列化方式,默认 JdkSerializationRedisSerializer * * @param redisConnectionFactory {@link RedisConnectionFactory} + * @param jsonMapper Jackson 序列化器(统一使用不写入类型信息的配置) * @return {@link RedisTemplate} */ @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory, + JsonMapper jsonMapper) { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); @@ -37,10 +39,6 @@ public class RedisConfig { redisTemplate.setHashKeySerializer(RedisSerializer.string()); // Value 使用自定义 JSON 序列化(不写入类型信息,避免 HashSet 等集合被序列化成带 @class 的结构) - JsonMapper jsonMapper = JsonMapper.builder() - .disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS) - .build(); - JacksonJsonRedisSerializer jsonSerializer = new JacksonJsonRedisSerializer<>(jsonMapper, Object.class); redisTemplate.setValueSerializer(jsonSerializer); @@ -50,4 +48,17 @@ public class RedisConfig { return redisTemplate; } + /** + * 统一的 JsonMapper Bean + *

+ * 禁止将日期序列化为时间戳;不写入类型信息,保证 Redis 存储的 JSON 纯净可读。 + * 需要反序列化到特定类型时,调用方应使用 {@link JsonMapper#convertValue(Object, Class)} 显式转换。 + */ + @Bean + public JsonMapper jsonMapper() { + return JsonMapper.builder() + .disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS) + .build(); + } + } diff --git a/src/main/java/com/youlai/boot/framework/security/token/RedisTokenManager.java b/src/main/java/com/youlai/boot/framework/security/token/RedisTokenManager.java index f58ab324..52481ad4 100644 --- a/src/main/java/com/youlai/boot/framework/security/token/RedisTokenManager.java +++ b/src/main/java/com/youlai/boot/framework/security/token/RedisTokenManager.java @@ -19,6 +19,8 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Service; +import tools.jackson.databind.json.JsonMapper; + import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -46,10 +48,14 @@ public class RedisTokenManager implements TokenManager { private final SecurityProperties securityProperties; private final RedisTemplate redisTemplate; + private final JsonMapper jsonMapper; - public RedisTokenManager(SecurityProperties securityProperties, RedisTemplate redisTemplate) { + public RedisTokenManager(SecurityProperties securityProperties, + RedisTemplate redisTemplate, + JsonMapper jsonMapper) { this.securityProperties = securityProperties; this.redisTemplate = redisTemplate; + this.jsonMapper = jsonMapper; } /** @@ -96,8 +102,9 @@ public class RedisTokenManager implements TokenManager { */ @Override public Authentication parseToken(String token) { - UserSession userSession = (UserSession) redisTemplate.opsForValue().get(formatTokenKey(token)); - if (userSession == null) return null; + Object raw = redisTemplate.opsForValue().get(formatTokenKey(token)); + if (raw == null) return null; + UserSession userSession = jsonMapper.convertValue(raw, UserSession.class); // 构建用户权限集合 Set authorities = null; @@ -144,11 +151,12 @@ public class RedisTokenManager implements TokenManager { */ @Override public AuthenticationToken refreshToken(String refreshToken) { - UserSession userSession = (UserSession) redisTemplate.opsForValue() + Object raw = redisTemplate.opsForValue() .get(StrUtil.format(RedisConstants.Auth.REFRESH_TOKEN_USER, refreshToken)); - if (userSession == null) { + if (raw == null) { throw new TokenInvalidException(ResultCode.REFRESH_TOKEN_INVALID); } + UserSession userSession = jsonMapper.convertValue(raw, UserSession.class); Object oldAccessTokenValue = redisTemplate.opsForValue().get(StrUtil.format(RedisConstants.Auth.USER_ACCESS_TOKEN, userSession.getUserId())); // 删除旧的访问令牌记录 Optional.of(oldAccessTokenValue)