Spring Cloud Gateway(以下簡稱 SCG)做為網(wǎng)關(guān)服務(wù),是其他各服務(wù)對外中轉(zhuǎn)站爽柒,通過 SCG 進(jìn)行請求轉(zhuǎn)發(fā)者填。
在請求到達(dá)真正的微服務(wù)之前,我們可以在這里做一些預(yù)處理占哟,比如:來源合法性檢測酿矢,權(quán)限校驗怎燥,反爬蟲之類…
之前是在各個微服務(wù)的攔截器里對來解密驗證的,現(xiàn)在既然有了網(wǎng)關(guān)策肝,自然而然想把這一步驟放到網(wǎng)關(guān)層來統(tǒng)一解決
image.png
如果是使用普通的 Web 編程中(比如用 Zuul)隐绵,這本就是一個 pre filter 的事兒依许,把之前 Interceptor 中代碼搬過來稍微改改就 OK 了。
不過因為使用的 SCG膘婶,它基于 Spring 5 的 WebFlux蛀醉,即 Reactor 編程,要讀取 Request Body 中的請求參數(shù)就沒那么容易了滞欠。
創(chuàng)建自定義過濾器繼承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";
}
/**
* 判斷用戶權(quán)限
*
* @param exchange
* @param requestParameters
* @return
*/
private boolean validateApiPermission(ServerWebExchange exchange, Map<String,Object> requestParameters) {
log.debug("接口請求參數(shù):{}", requestParameters);
/***實現(xiàn)
}
}
至于拿到 Body 后具體要做什么惹恃,就由你自己來發(fā)揮吧
我這里是做了整個平臺服務(wù)的鑒權(quán)功能。
在配置文件里添加修改
predicates:
- Path=/openapi/**
filters:
- AuthorizationSignature
- ReqApiPermission
- RewritePath=/openapi/(?<remaining>.*), /${remaining}
這樣同樣的路徑可以會被兩個過濾器同時過濾朗儒。
其他的實現(xiàn)方式可參考如下鏈接:https://www.cnblogs.com/hyf-huangyongfei/p/12849406.html