一、ReactiveRedisTemplate 应用 fastjson 进行序列化配置
- 首先在 maven 中引入 reactive redis 包和 fastjson 包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
- 编写 RedisAutoConfig.class 进行自定义 ReactiveRedisTemplate Bean 配置
我这里应用的是 ReactiveRedisTemplate<String, Object>,key 为 String 类型,value 为 Object 类型,这样 value 能够间接应用 Java 对象操作,不须要显示进行 fastjson 的序列化和反序列化。
须要留神的是 new ReactiveRedisTemplate 时须要传入 1 个 RedisSerializationContext 对象,redis 的 key、value 序列化形式就配置在 RedisSerializationContext 中。
这里咱们应用 StringRedisSerializer 进行 key 和 hashKey 的序列化,应用 fastjson 的 GenericFastJsonRedisSerializer 进行 value 和 hashValue 的序列化。
@Configuration
public class RedisAutoConfig {
@Bean
public ReactiveRedisTemplate<String, Object> reactiveRedisTemplate(LettuceConnectionFactory connectionFactory) {StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
GenericFastJsonRedisSerializer fastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
RedisSerializationContext.SerializationPair<String> keySerializationPair =
RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer);
RedisSerializationContext.SerializationPair<Object> valueSerializationPair =
RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer);
RedisSerializationContext.SerializationPair<Object> hashValueSerializationPair =
RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer);
RedisSerializationContext<String, Object> context = new RedisSerializationContext<String, Object>() {
@Override
public SerializationPair getKeySerializationPair() {return keySerializationPair;}
@Override
public SerializationPair getValueSerializationPair() {return valueSerializationPair;}
@Override
public SerializationPair getHashKeySerializationPair() {return keySerializationPair;}
@Override
public SerializationPair getHashValueSerializationPair() {return hashValueSerializationPair;}
@Override
public SerializationPair<String> getStringSerializationPair() {return keySerializationPair;}
};
return new ReactiveRedisTemplate<>(connectionFactory, context);
}
}
这样配置实现后,就能够间接主动注入 ReactiveRedisTemplate<String, Object> 对象
@Autowired
private ReactiveRedisTemplate<String, Object> reactiveRedisTemplate;
二、在 SpringCloudGateway 中应用 ReactiveRedisTemplate 进行自定义 token 校验
- 首先在 maven 中引入 spring cloud gateway 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
- 编写自定义 filter factory TokenVerifyGatewayFilterFactory 进行自定义 token 校验
首先从 request 的 header 中取出 token 字段,依据 token 查问 redis,取出 token 对应的用户 id,如果用户 id 存在则 token 无效,如果不存在则返回 token 有效。
@Component
public class TokenVerifyGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
@Autowired
private ReactiveRedisTemplate<String, Object> reactiveRedisTemplate;
@Override
public GatewayFilter apply(Object config) {return (exchange, chain) -> {ServerHttpRequest request = exchange.getRequest();
String token = request.getHeaders().get("token").get(0);
return this.getUserId(token).flatMap(op -> {
//1、判断 redis 中是否存在对应缓存,不存在则间接返回 token 有效
if (!op.isPresent()) {ServerHttpResponse response = exchange.getResponse();
byte[] bits = "token 有效".getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
//2、缓存无效,获取 userId,进行日志记录或者其余操作
System.out.println("redis 缓存 token 用户:" + op.get());
//3、token 鉴权通过,继续执行 filter 实现转发
return chain.filter(exchange);
});
};
}
private Mono<Optional<String>> getUserId(String token) {
//a、以 reactive 的形式查问 redis,获取 token 对应 value 值
return this.reactiveRedisTemplate.opsForValue().get(token)
//b、对 redis 返回后果进行 Optional 封装,这里 v 为 String 类型的用户 id
.map(v -> Optional.ofNullable((String)v))
//c、如果 token 有效,b 不会执行,在这里返回 1 个值为 null 的 Optional 对象
.switchIfEmpty(Mono.just(Optional.ofNullable(null)));
}
}
三、测试
- 编写 SpringCloudGateway 配置文件
对于任意 uri,都应用 TokenVerifyGatewayFilterFactory 进行申请过滤,并将 localhost:8080 的任意申请转发至 https://www.baidu.com。
spring:
cloud:
gateway:
routes:
- id: testRoute
uri: https://www.baidu.com
predicates:
- Path=/**
filters:
- TokenVerify
- Redis 缓存数据设置
在 Redis 中缓存 key=”goodToken”,value=”magicTan”,即 goodToken 是非法 token,用户 id 为 magicTan。如果应用不非法 token 如 invalidToken 就无奈取到用户 id。
- 运行我的项目进行测试
调用 localhost:8080,header 中设置 token 为 goodToken,能够看到申请转发至百度,并且控制台输入了缓存的用户 id magicTan:
调用 localhost:8080,header 中设置 token 为 invalidToken,能够看到返回后果为“token 有效”:
我的项目地址:码云
欢送扫码关注我微信公众号:magicTan。