如何在网关转发之前做登录校验?
网关请求处理流程
如何在网关转发之前做登录校验?
网关如何将用户信息传递给微服务?
如何在微服务之间传递用户信息?
自定义过滤器
网关过滤器有两种,分别是:
- GatewayFilter:路由过滤器,作用于任意指定的路由;默认不生效,要配置到路由后生效。
- GlobalFilter:全局过滤器,作用范围是所有路由;声明后自动生效。
两种过滤器的过滤方法签名完全一致:
自定义GlobalFilter比较简单,直接实现GlobalFilter接口即可:
自定义GatewayFilter不是直接实现GatewayFilter,而是实现AbstractGatewayFilterFactory,示例如下:
实现登录校验
黑马商城是基于JWT实现的登录校验,目前相关功能在hm-service模块。我们可以将其中的JWT工具拷贝到gateway模块,然后基于GlobalFilter来实现登录校验。
AuthGlobalFilter
@Component
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private final AuthProperties authProperties;
private final JwtTool jwtTool;
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
if (isExclude(request.getPath().toString())){
return chain.filter(exchange);
}
List<String> headers = request.getHeaders().get("authorization");
String token = null;
if (headers != null && !headers.isEmpty()){
token = headers.get(0);
}
Long userId = null;
try {
userId = jwtTool.parseToken(token);
} catch (Exception e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
String userInfo = userId.toString();
ServerWebExchange swe = exchange.mutate()
.request(builder -> builder.header("user-info", userInfo))
.build();
return chain.filter(swe);
}
private boolean isExclude(String path) {
for (String pathPattern : authProperties.getExcludePaths()) {
if (antPathMatcher.match(pathPattern, path)) {
return true;
}
}
return false;
}
@Override
public int getOrder() {
return 0;
}
}
网关传递用户
在网关的登录校验过滤器中,把获取到的用户写入请求头
要修改转发到微服务的请求,需要用到ServerWebExchange类提供的API,示例如下:
在hm-common中编写SpringMVC拦截器,获取登录用户
由于每个微服务都可能有获取登录用户的需求,因此我们直接在hm-common模块定义拦截器,这样微服务只需要引入依赖即可生效,无需重复编写。
OpenFeign传递用户
微服务项目中的很多业务要多个微服务共同合作完成,而这个过程中也需要传递登录用户信息,例如:
OpenFeign中提供了一个拦截器接口,所有由OpenFeign发起的请求都会先调用拦截器处理请求:
其中的RequestTemplate类中提供了一些方法可以让我们修改请求头: