前言
在上一篇文章《Soul网关源码学习(17)- 限流:RateLimiterPlugin》中,我们学习了 RateLimiterPlugin 的使用,并且分析了其实现原理。那这一篇我们再来学习另外一个插件:防火墙插件 WafPlugin。
WafPlugin 的使用
waf插件,是网关的用来对流量实现防火墙功能的核心实现,现在我们就先来看一下它到底是怎么使用的。
和其他插件一样,先引入依赖:
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-waf</artifactId>
<version>${project.version}</version>
</dependency>
然后登录控制台 -> 系统管理 -> 插件管理 -> 列表中选择 waf -> 点击右边编辑按钮:
- 当 module 设置为 black 模式的时候,只有匹配的流量才会执行拒绝策略,不匹配的,直接会跳过.
- 当 module 设置为 mixed 模式的时候,所有的流量都会通过 waf插件,针对不同的匹配流量,用户可以设置是 拒绝,还是通过。
添加选择器,控制台 -> 插件列表 -> waf -> 添加选择器按钮:
- 注意:如果本地测试最好是使用 127.0.0.1 来进行测试,而不是 localhost。
为接口添加防火墙规则:控制台 -> 插件列表 -> waf -> 添加规则按钮:
使用postman测试:
我们再把 permission 改成 allow:
再进行访问:
WafPlugin 源码分析
WafPlugin 的逻辑还是比较简单的,下面是其 doExecutor 方法:
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)) {
//如防火墙规则是 black,则直接跳过(黑名单只拦截匹配的流量,不匹配的会跳过)
if (WafModelEnum.BLACK.getName().equals(wafConfig.getModel())) {
return chain.execute(exchange);
}
//如果是 mixed 模式,所有流量都会通过 waf,所以没有配置选择器规则的流量会被拒绝
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
Object error = SoulResultWrap.error(HttpStatus.FORBIDDEN.value(), Constants.REJECT_MSG, null);
return WebFluxResultUtils.result(exchange, error);
}
String handle = rule.getHandle();
//如果规则为空或者 permission 为空,则直接跳过。
//所以这里注意:在 mixed 模式下,选择器为空是会被拦截的,但是规则是默认通过的。
WafHandle wafHandle = GsonUtils.getInstance().fromJson(handle, WafHandle.class);
if (Objects.isNull(wafHandle) || StringUtils.isBlank(wafHandle.getPermission())) {
log.error("waf handler can not configuration:{}", handle);
return chain.execute(exchange);
}
//如果是拒接策略
if (WafEnum.REJECT.getName().equals(wafHandle.getPermission())) {
//状态码默认403
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);
}
总结
到这里,WafPlugin 就学习并且分析完了,总体来说还是比较简单的,其代码实现并不难看懂,至于使用上,最主要是你的选择器和规则要玩的溜,这也是 Soul 所有插件的一个共同的特性,对于这一方面,小伙伴们可以去参考一下官方对选择器和规则的说明,后续会继续带来 soul 网关其他插件或者模块的源码解读。