最近项目从spring zuul切换到spring gateway,原来项目中用户登录权限存储在redis中,使用了StringRedisTemplate对redis操作。为了方便准备接拷贝验证部分代码。但在请求执行过滤器时候发现StringRedisTemplate为null。当时第一反应是Filter加载顺序问题,但随即想到,在过滤器执行的时候Bean已经在Spring容器中加载完成了(具体可以看spring源码,这里不做详述)。下面贴一下最初关键代码
1、yml中关键配置
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: hb-balance-server
uri: lb://hb-balance-server
predicates:
- Path=/balance/**
filters:
- StripPrefix=0
- Auth
2、将过滤器加载到容器中
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
@Override
public GatewayFilter apply(Object config) {
return new AuthGatewayFilter();
}
}
3、实现过滤器权限验证
import cn.synline.gateway.server.redis.AuthRedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Slf4j
@Component
public class AuthGatewayFilter implements GatewayFilter, Ordered {
@Autowired
private AuthRedisService authRedisService;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
MultiValueMap<String, HttpCookie> cookieMultiValueMap = exchange.getRequest().getCookies();
String token = CookieUtil.token(cookieMultiValueMap);
String userInfo = authRedisService.loginUserInfo(token);
log.info("token:{},userInfo:{}",token,userInfo);
if (userInfo != null){
return chain.filter(exchange);
} else {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
@Override
public int getOrder() {
return 1;
}
}
系统运行时,authRedisService为null。因为过滤器对象是new 出来的,所以这个过滤器下是不能通过@Autowired获取容器对象
稍微调整一下,这个对象在初始化的时候我们从spring 容器中获得,代码如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
@Autowired
private AuthGatewayFilter authGatewayFilter;
@Override
public GatewayFilter apply(Object config) {
return authGatewayFilter;
}
}
然后直接跑一下看效果
已经可以拿到对象了。OK了
在使用spring gateway的自定义过滤器时还需要注意,“AuthGatewayFilterFactory” 这个工厂名称要遵循Spring约定,我的过滤器在yml配置中名称为Auth。xxx + GatewayFilterFactory,XXX为过滤器名称