waf 插件和 rewrite 插件
waf 插件
简介
waf 插件是 soul 的前置插件,主要用来拦截非法请求,或者异常请求,并且给与相关的拒绝策略,是 soul 网关的用来对流量实现防火墙功能的核心实现。
使用
1)首先在 soul-admin 中开启 waf 插件
2)soul-bootstrap 的 pom 文件中添加 waf 插件starter 的依赖
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-waf</artifactId>
<version>${project.version}</version>
</dependency>
3)然后在 soul-admin 的 waf 插件中添加 过滤器 和 规则 对非法请求/异常请求进行拒绝
这里将 URL 为 /waf/test 的请求设置为拒绝,返回的状态码设置为 429:
请求 http://localhost:9195/waf/test 便会被直接拒绝:
{
"code": 426,
"message": " You are forbidden to visit",
"data": null
}
源码分析
waf 插件关键源码解读:
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
// 拿到流量防火墙配置,默认是黑名单模式
WafConfig wafConfig = Singleton.INST.get(WafConfig.class);
if (Objects.isNull(selector) && Objects.isNull(rule)) {
// waf插件如果没有配置选择器和规则,而且是黑名单模式的话,请求会被放行到下一个插件
if (WafModelEnum.BLACK.getName().equals(wafConfig.getModel())) {
return chain.execute(exchange);
}
// 如果是混合模式,会返回 403
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
Object error = SoulResultWrap.error(403, Constants.REJECT_MSG, null);
return WebFluxResultUtils.result(exchange, error);
}
// 拿到匹配的规则,如:{"permission":"reject","statusCode":"426"}
String handle = rule.getHandle();
// 将规则转换成 WafHandle 类型,如:WafHandle(permission=reject, statusCode=426)
WafHandle wafHandle = GsonUtils.getInstance().fromJson(handle, WafHandle.class);
if (Objects.isNull(wafHandle) || StringUtils.isBlank(wafHandle.getPermission())) {
// 没有 WafHandle ,请求就直接放行
log.error("waf handler can not configuration:{}", handle);
return chain.execute(exchange);
}
// 如果当前规则配置的是:拒绝访问
if (WafEnum.REJECT.getName().equals(wafHandle.getPermission())) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
// 从规则中拿出配置的状态码并返回
Object error = SoulResultWrap.error(Integer.parseInt(wafHandle.getStatusCode()), Constants.REJECT_MSG, null);
return WebFluxResultUtils.result(exchange, error);
}
// 当前请求被允许,则放行请求
return chain.execute(exchange);
}
waf 插件总结
总的来说,waf 插件就相当于一个全局的请求拦截器,当请求属于黑名单的时候,会直接拒绝请求,反之,则放心请求到下一个插件。比较灵活的一点是:请求的黑白名单,可以在 soul-admin 中通过选择器和规则进行方便的配置。
rewrite 插件
简介
rewrite 插件用来对请求 URI 进行重新定义。当匹配到请求之后,如果设置了自定义路径,那么自定义的路径就会覆盖之前的请求路径。
使用
1)首先在 soul-admin 中开启 rewrite 插件
2)soul-bootstrap 的 pom 文件中添加 rewrite 插件starter 的依赖
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-rewrite</artifactId>
<version>${project.version}</version>
</dependency>
3) 然后在 soul-admin 的 rewrite 插件中添加 过滤器 和 规则 对请求 URI 进行重写
源码分析
rewrite 插件关键源码解读:
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
// 从匹配到的规则中获取 handle,如:{"rewriteURI":"/http/order/findById"}
String handle = rule.getHandle();
// 转换成 RewriteHandle,如:RewriteHandle(rewriteURI=/http/order/findById)
final RewriteHandle rewriteHandle = GsonUtils.getInstance().fromJson(handle, RewriteHandle.class);
if (Objects.isNull(rewriteHandle) || StringUtils.isBlank(rewriteHandle.getRewriteURI())) {
// 没有匹配到,则直接放行请求,不做重写处理
log.error("uri rewrite rule can not configuration:{}", handle);
return chain.execute(exchange);
}
// 设置 exchange 的 rewrite_uri 属性,实现请求URI 的重写
exchange.getAttributes().put(Constants.REWRITE_URI, rewriteHandle.getRewriteURI());
// 将新的 URI 放行到下一个插件
return chain.execute(exchange);
}
rewrite 插件总结
总的来说,rewrite 插件也相当于一个全局的请求拦截器,当请求经过 rewrite 插件时,如果匹配到了在 soul-admin 中配置的规则,那么会通过设置 exchange 的 rewrite_uri 属性,来实现对请求 URI 的重写。