Skip to content

Commit b5ec3f4

Browse files
✨ 将储存在 Redis 中的数据序列化为 JSON(本功能不兼容之前的Redis数据,需要将原有Redis数据清空才能正常使用)
spring-projects/spring-security#4370
1 parent d79f5ec commit b5ec3f4

File tree

9 files changed

+241
-45
lines changed

9 files changed

+241
-45
lines changed

pig-common/pig-common-core/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,11 @@
6161
<artifactId>spring-webmvc</artifactId>
6262
<scope>provided</scope>
6363
</dependency>
64+
<dependency>
65+
<groupId>org.springframework.security</groupId>
66+
<artifactId>spring-security-oauth2-authorization-server</artifactId>
67+
<version>${spring.authorization.version}</version>
68+
<scope>provided</scope>
69+
</dependency>
6470
</dependencies>
6571
</project>

pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/config/JacksonConfiguration.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,10 @@
1717
package com.pig4cloud.pig.common.core.config;
1818

1919
import cn.hutool.core.date.DatePattern;
20-
import com.fasterxml.jackson.databind.ObjectMapper;
2120
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
2221
import com.pig4cloud.pig.common.core.jackson.PigJavaTimeModule;
23-
import org.springframework.boot.autoconfigure.AutoConfiguration;
24-
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
25-
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2622
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2723
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
28-
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
2924
import org.springframework.context.annotation.Bean;
3025

3126
import java.time.ZoneId;
@@ -40,9 +35,9 @@
4035
* @author lishangbu
4136
* @date 2020-06-17
4237
*/
43-
@AutoConfiguration
44-
@ConditionalOnClass(ObjectMapper.class)
45-
@AutoConfigureBefore(JacksonAutoConfiguration.class)
38+
// @EnableCaching
39+
// @AutoConfiguration
40+
// @AutoConfigureBefore(RedisAutoConfiguration.class)
4641
public class JacksonConfiguration {
4742

4843
@Bean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package com.pig4cloud.pig.common.core.config;
2+
3+
import cn.hutool.core.date.DatePattern;
4+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
5+
import com.fasterxml.jackson.databind.DeserializationFeature;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.SerializationFeature;
8+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
9+
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
10+
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
11+
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
12+
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
13+
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
14+
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
15+
import org.springframework.beans.factory.annotation.Autowired;
16+
import org.springframework.boot.autoconfigure.AutoConfiguration;
17+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
18+
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
19+
import org.springframework.cache.annotation.EnableCaching;
20+
import org.springframework.context.annotation.Bean;
21+
import org.springframework.data.redis.cache.RedisCacheConfiguration;
22+
import org.springframework.data.redis.cache.RedisCacheManager;
23+
import org.springframework.data.redis.cache.RedisCacheWriter;
24+
import org.springframework.data.redis.connection.RedisConnectionFactory;
25+
import org.springframework.data.redis.core.RedisTemplate;
26+
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
27+
import org.springframework.data.redis.serializer.RedisSerializationContext;
28+
import org.springframework.data.redis.serializer.RedisSerializer;
29+
import org.springframework.data.redis.serializer.StringRedisSerializer;
30+
import org.springframework.security.jackson2.CoreJackson2Module;
31+
import org.springframework.security.jackson2.SecurityJackson2Modules;
32+
import org.springframework.security.web.jackson2.WebJackson2Module;
33+
import org.springframework.security.web.jackson2.WebServletJackson2Module;
34+
import org.springframework.security.web.server.jackson2.WebServerJackson2Module;
35+
36+
import java.time.LocalDate;
37+
import java.time.LocalDateTime;
38+
import java.time.LocalTime;
39+
import java.time.format.DateTimeFormatter;
40+
import java.util.Objects;
41+
42+
/**
43+
* Redis 缓存管理器 配置
44+
* <p>
45+
* 可将 Redis 内的数据格式化为 JSON
46+
* <p>
47+
* 与 {@link RedisTemplateConfiguration} 二选一
48+
*
49+
* @author xuxiaowei
50+
* @since 3.6.4
51+
*/
52+
@EnableCaching
53+
@AutoConfiguration
54+
@AutoConfigureBefore(RedisAutoConfiguration.class)
55+
public class RedisCacheManagerConfiguration {
56+
57+
/**
58+
* Redis 缓存管理器
59+
* @param redisTemplate Redis 模板
60+
* @return 返回 Redis 缓存管理器
61+
*/
62+
@Bean
63+
public RedisCacheManager redisCacheManager(RedisTemplate<?, ?> redisTemplate) {
64+
65+
// 从 RedisTemplate 中获取连接
66+
RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
67+
68+
// 检查 RedisConnectionFactory 是否为 null
69+
RedisConnectionFactory redisConnectionFactory = Objects.requireNonNull(connectionFactory);
70+
71+
// 检查 RedisConnectionFactory 是否为 null
72+
// 创建新的无锁 RedisCacheWriter
73+
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
74+
75+
// 获取 RedisTemplate 的序列化
76+
RedisSerializer<?> valueSerializer = redisTemplate.getValueSerializer();
77+
78+
// 序列化对
79+
RedisSerializationContext.SerializationPair<?> serializationPair = RedisSerializationContext.SerializationPair
80+
.fromSerializer(valueSerializer);
81+
82+
// 获取默认缓存配置
83+
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
84+
85+
// 设置序列化
86+
RedisCacheConfiguration redisCacheConfigurationSerialize = redisCacheConfiguration
87+
.serializeValuesWith(serializationPair);
88+
89+
// 创建并返回 Redis 缓存管理
90+
return new RedisCacheManager(redisCacheWriter, redisCacheConfigurationSerialize);
91+
}
92+
93+
/**
94+
* 注意:如果要使用注解 {@link Autowired} 管理 {@link RedisTemplate}, 则需要将 {@link RedisTemplate} 的
95+
* {@link Bean} 缺省泛型
96+
* @param redisConnectionFactory Redis 连接工厂
97+
* @return 返回 Redis 模板
98+
*/
99+
@Bean
100+
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
101+
102+
// Helper类简化了 Redis 数据访问代码
103+
RedisTemplate<String, Object> template = new RedisTemplate<>();
104+
105+
// 设置连接工厂。
106+
template.setConnectionFactory(redisConnectionFactory);
107+
108+
// 可以使用读写JSON
109+
Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
110+
111+
jackson2JsonRedisSerializer.setObjectMapper(objectMapper());
112+
113+
// Redis 字符串:键、值序列化
114+
template.setKeySerializer(new StringRedisSerializer());
115+
template.setValueSerializer(jackson2JsonRedisSerializer);
116+
117+
// Redis Hash:键、值序列化
118+
template.setHashKeySerializer(new StringRedisSerializer());
119+
template.setHashValueSerializer(jackson2JsonRedisSerializer);
120+
121+
template.afterPropertiesSet();
122+
123+
return template;
124+
}
125+
126+
public static ObjectMapper objectMapper() {
127+
// ObjectMapper 提供了从基本 POJO(普通旧Java对象)或从通用 JSON 树模型({@link JsonNode})读取和写入 JSON
128+
// 的功能,
129+
// 以及执行转换的相关功能。
130+
ObjectMapper objectMapper = new ObjectMapper();
131+
132+
// 枚举,定义影响Java对象序列化方式的简单开/关功能。
133+
// 默认情况下启用功能,因此默认情况下日期/时间序列化为时间戳。
134+
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
135+
// 如果启用,上下文<code> TimeZone </
136+
// code>将基本上覆盖任何其他TimeZone信息;如果禁用,则仅在值本身不包含任何TimeZone信息时使用。
137+
objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
138+
139+
// 注册使用Jackson核心序列化{@code java.time}对象的功能的类。
140+
JavaTimeModule javaTimeModule = new JavaTimeModule();
141+
142+
// 添加序列化
143+
javaTimeModule.addSerializer(LocalDateTime.class,
144+
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
145+
javaTimeModule.addSerializer(LocalDate.class,
146+
new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
147+
javaTimeModule.addSerializer(LocalTime.class,
148+
new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
149+
150+
// 添加反序列化
151+
javaTimeModule.addDeserializer(LocalDateTime.class,
152+
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
153+
javaTimeModule.addDeserializer(LocalDate.class,
154+
new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
155+
javaTimeModule.addDeserializer(LocalTime.class,
156+
new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
157+
158+
// 用于注册可以扩展该映射器提供的功能的模块的方法; 例如,通过添加自定义序列化程序和反序列化程序的提供程序。
159+
objectMapper.registerModule(javaTimeModule);
160+
161+
// Web、Security 序列化与反序列化
162+
// 显性引入
163+
// https://github.com/spring-projects/spring-security/issues/4370
164+
SecurityJackson2Modules.enableDefaultTyping(objectMapper);
165+
objectMapper.registerModules(new WebServletJackson2Module(), new WebJackson2Module(), new CoreJackson2Module(),
166+
new WebServerJackson2Module());
167+
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),
168+
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
169+
// objectMapper.registerModule(new CasJackson2Module());
170+
// objectMapper.registerModule(new OAuth2ClientJackson2Module());
171+
// objectMapper.registerModule(new Saml2Jackson2Module());
172+
173+
return objectMapper;
174+
}
175+
176+
}

pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/config/RedisTemplateConfiguration.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,20 @@
1616

1717
package com.pig4cloud.pig.common.core.config;
1818

19-
import org.springframework.boot.autoconfigure.AutoConfiguration;
20-
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
21-
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
22-
import org.springframework.cache.annotation.EnableCaching;
2319
import org.springframework.context.annotation.Bean;
2420
import org.springframework.data.redis.connection.RedisConnectionFactory;
2521
import org.springframework.data.redis.core.*;
2622
import org.springframework.data.redis.serializer.RedisSerializer;
2723

2824
/**
25+
* 与 {@link RedisCacheManagerConfiguration} 二选一
26+
*
2927
* @author lengleng
3028
* @date 2019/2/1 Redis 配置类
3129
*/
32-
@EnableCaching
33-
@AutoConfiguration
34-
@AutoConfigureBefore(RedisAutoConfiguration.class)
30+
// @EnableCaching
31+
// @AutoConfiguration
32+
// @AutoConfigureBefore(RedisAutoConfiguration.class)
3533
public class RedisTemplateConfiguration {
3634

3735
@Bean
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
com.pig4cloud.pig.common.core.config.TaskExecutorConfiguration
22
com.pig4cloud.pig.common.core.config.JacksonConfiguration
3-
com.pig4cloud.pig.common.core.config.RedisTemplateConfiguration
3+
com.pig4cloud.pig.common.core.config.RedisCacheManagerConfiguration
44
com.pig4cloud.pig.common.core.config.RestTemplateConfiguration
55
com.pig4cloud.pig.common.core.util.SpringContextHolder
66
com.pig4cloud.pig.common.core.config.WebMvcConfiguration

pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigAppUserDetailsServiceImpl.java

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
import lombok.RequiredArgsConstructor;
2525
import lombok.SneakyThrows;
2626
import lombok.extern.slf4j.Slf4j;
27-
import org.springframework.cache.Cache;
28-
import org.springframework.cache.CacheManager;
27+
import org.springframework.cache.annotation.Cacheable;
2928
import org.springframework.security.core.userdetails.UserDetails;
3029

3130
/**
@@ -39,28 +38,17 @@ public class PigAppUserDetailsServiceImpl implements PigUserDetailsService {
3938

4039
private final RemoteUserService remoteUserService;
4140

42-
private final CacheManager cacheManager;
43-
4441
/**
4542
* 手机号登录
4643
* @param phone 手机号
4744
* @return
4845
*/
4946
@Override
5047
@SneakyThrows
48+
@Cacheable(value = CacheConstants.USER_DETAILS, key = "#phone", unless = "#result == null")
5149
public UserDetails loadUserByUsername(String phone) {
52-
Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
53-
if (cache != null && cache.get(phone) != null) {
54-
return (PigUser) cache.get(phone).get();
55-
}
56-
5750
R<UserInfo> result = remoteUserService.infoByMobile(phone);
58-
59-
UserDetails userDetails = getUserDetails(result);
60-
if (cache != null) {
61-
cache.put(phone, userDetails);
62-
}
63-
return userDetails;
51+
return getUserDetails(result);
6452
}
6553

6654
/**

pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@
2323
import lombok.RequiredArgsConstructor;
2424
import lombok.SneakyThrows;
2525
import lombok.extern.slf4j.Slf4j;
26-
import org.springframework.cache.Cache;
27-
import org.springframework.cache.CacheManager;
26+
import org.springframework.cache.annotation.Cacheable;
2827
import org.springframework.context.annotation.Primary;
2928
import org.springframework.security.core.userdetails.UserDetails;
3029

@@ -40,27 +39,17 @@ public class PigUserDetailsServiceImpl implements PigUserDetailsService {
4039

4140
private final RemoteUserService remoteUserService;
4241

43-
private final CacheManager cacheManager;
44-
4542
/**
4643
* 用户名密码登录
4744
* @param username 用户名
4845
* @return
4946
*/
5047
@Override
5148
@SneakyThrows
49+
@Cacheable(value = CacheConstants.USER_DETAILS, key = "#username", unless = "#result == null")
5250
public UserDetails loadUserByUsername(String username) {
53-
Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
54-
if (cache != null && cache.get(username) != null) {
55-
return (PigUser) cache.get(username).get();
56-
}
57-
5851
R<UserInfo> result = remoteUserService.info(username);
59-
UserDetails userDetails = getUserDetails(result);
60-
if (cache != null) {
61-
cache.put(username, userDetails);
62-
}
63-
return userDetails;
52+
return getUserDetails(result);
6453
}
6554

6655
@Override

pig-gateway/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@
9292
<groupId>org.springdoc</groupId>
9393
<artifactId>springdoc-openapi-webflux-ui</artifactId>
9494
</dependency>
95+
<dependency>
96+
<groupId>org.springframework.security</groupId>
97+
<artifactId>spring-security-oauth2-authorization-server</artifactId>
98+
<version>${spring.authorization.version}</version>
99+
</dependency>
95100
</dependencies>
96101

97102
<build>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.pig4cloud.pig.gateway.config;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.security.authorization.AuthorizationDecision;
7+
import org.springframework.security.authorization.ReactiveAuthorizationManager;
8+
import org.springframework.security.config.web.server.ServerHttpSecurity;
9+
import org.springframework.security.core.Authentication;
10+
import org.springframework.security.web.server.SecurityWebFilterChain;
11+
import org.springframework.security.web.server.authorization.AuthorizationContext;
12+
import reactor.core.publisher.Mono;
13+
14+
/**
15+
* 网关禁用 Security
16+
*
17+
* @author xuxiaowei
18+
* @since 3.6.4
19+
*/
20+
@Slf4j
21+
@Configuration
22+
public class ReactiveAuthorizationManagerConfiguration implements ReactiveAuthorizationManager<AuthorizationContext> {
23+
24+
@Override
25+
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext object) {
26+
return Mono.just(new AuthorizationDecision(true));
27+
}
28+
29+
@Bean
30+
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
31+
32+
http.formLogin().disable();
33+
http.csrf().disable();
34+
http.cors().disable();
35+
36+
return http.build();
37+
}
38+
39+
}

0 commit comments

Comments
 (0)