Spring Cloud Gateway(以下简称 SCG)做为网关服务,是其他各服务对外中转站,通过 SCG 进行请求转发。 在请求到达真正的微服务之前,我们可以在这里做一些预处理,比如:来源合法性检测,权限校验,反爬虫之类… 之前是在各个微服务的拦截器里对来解密验证的,现在既然有了网关,自然而然想把这一步骤放到网关层来统一解决
如果是使用普通的 Web 编程中(比如用 Zuul),这本就是一个 pre filter 的事儿,把之前 Interceptor 中代码搬过来稍微改改就 OK 了。 不过因为使用的 SCG,它基于 Spring 5 的 WebFlux,即 Reactor 编程,要读取 Request Body 中的请求参数就没那么容易了。 创建自定义过滤器继承AbstractGatewayFilterFactory
@Component
@Slf4j
public class ReqApiPermissionFilterFactory extends AbstractGatewayFilterFactory<ReqApiPermissionFilterFactory.Config> {
public ReqApiPermissionFilterFactory() {
super(ReqApiPermissionFilterFactory.Config.class);
}
static class Config {
}
@Value("${token.user.url}")
String userURL;
@Value("${middle.platform.url}")
String middlePlatformURL;
private static final String CONTENT_TYPE = "Content-Type";
private static final String CONTENT_TYPE_JSON = "application/json";
@Override
public GatewayFilter apply(ReqApiPermissionFilterFactory.Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String contentType = request.getHeaders().getFirst(CONTENT_TYPE);
String method = request.getMethodValue();
if (null != contentType && HttpMethod.POST.name().equalsIgnoreCase(method) && contentType.contains(CONTENT_TYPE_JSON)) {
ModifyRequestBodyGatewayFilterFactory.Config modifyRequestConfig = new ModifyRequestBodyGatewayFilterFactory.Config()
.setContentType(ContentType.APPLICATION_JSON.getMimeType())
.setRewriteFunction(Map.class, Map.class, (exchange1, originalRequestBody) -> {
boolean isPass = validateApiPermission(exchange1, originalRequestBody);
if(!isPass){
throw new ResultException(GatewayErrorCode.PERMISSION_ERROR,
ImmutableMap.of("originalRequestBody", originalRequestBody));
}
return Mono.just(originalRequestBody);
});
return new ModifyRequestBodyGatewayFilterFactory().apply(modifyRequestConfig).filter(exchange, chain);
}
if (HttpMethod.GET.name().equalsIgnoreCase(method)) {
Map<String,Object> query = request.getQueryParams().entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
boolean isPass = validateApiPermission(exchange, query);
if(!isPass){
throw new ResultException(GatewayErrorCode.PERMISSION_ERROR,
ImmutableMap.of("query", query));
}
return chain.filter(exchange.mutate().request(request).build());
}
return chain.filter(exchange);
};
}
@Override
public String name() {
return "ReqApiPermission";
}
/**
* 判断用户权限
*
* @param exchange
* @param requestParameters
* @return
*/
private boolean validateApiPermission(ServerWebExchange exchange, Map<String,Object> requestParameters) {
log.debug("接口请求参数:{}", requestParameters);
/***实现
}
}
至于拿到 Body 后具体要做什么,就由你自己来发挥吧
我这里是做了整个平台服务的鉴权功能。
在配置文件里添加修改
predicates:
- Path=/openapi/**
filters:
- AuthorizationSignature
- ReqApiPermission
- RewritePath=/openapi/(?<remaining>.*), /${remaining}
这样同样的路径可以会被两个过滤器同时过滤。
其他的实现方式可参考如下链接:www.cnblogs.com/hyf-huangyo…