赞
踩
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}
这样同样的路径可以会被两个过滤器同时过滤。
其他的实现方式可参考如下链接:Spring Cloud Gateway 之获取请求体(Request Body)的几种方式 - 码农的进击 - 博客园
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。