说明
- 本文将分析 Apache ShenYu 网关 waf、rewirte、contextpath插件具体应用,以及对应的源码分析
waf插件
waf,全称 web application firewall,也就是web应用防火墙。网关作为我们服务的入口,加入waf可以为我们的服务提供各种安全验证和拦截。shenyu 网关的 waf插件,更是可以提供非常灵活的waf规则配置,我们甚至可以为每一个接口配置不同的策略。
插件应用
- shenyu-admin -> 插件管理 -> waf 插件编辑 -> 开启插件
- shenyu-bootstrap 加上 waf插件的stater依赖,并重启服务。
<!-- shenyu waf plugin starter--> <dependency> <groupId>org.apache.shenyu</groupId> <artifactId>shenyu-spring-boot-starter-plugin-waf</artifactId> <version>${last.version}</version> </dependency> <!-- shenyu waf plugin end-->
- 选择器配置请参考Apache ShenYu 网关选择器和规则解析
- 规则配置:
- Dealing: reject(拒绝),allow(允许)
- status code: 如果拒绝,返回给请求方的code。
被waf拒绝后到返回值(code可以通过上面的方式自定义)
{"code":500,"message":" You are forbidden to visit","data":null}
源码分析
shenyu 网关 waf插件,在经过选择器和规则匹配上后,根据模式、规则的处理是拒绝还是允许,做对应的逻辑处理。拒绝,返回code和提示。允许,放行,流转到下一个插件。
核心源码:
public class WafPlugin extends AbstractShenyuPlugin {
@Override
protected Mono<Void> doExecute(final ServerWebExchange exchange, final ShenyuPluginChain chain, final SelectorData selector, final RuleData rule) {
……
//判断规则是拒绝,则直接返回错误信息
if (WafEnum.REJECT.getName().equals(wafHandle.getPermission())) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
Object error = ShenyuResultWrap.error(Integer.parseInt(wafHandle.getStatusCode()), Constants.REJECT_MSG, null);
return WebFluxResultUtils.result(exchange, error);
}
return chain.execute(exchange);
}
}
rewrite插件
rewrite插件提供对请求uri进行指定规则重写的功能
插件应用
- shenyu-admin -> 插件管理 -> rewrite插件编辑 -> 开启插件
- shenyu-bootstrap 项目中加入 rewrite插件依赖,并重启项目
<!-- shenyu rewrite plugin start--> <dependency> <groupId>org.apache.shenyu</groupId> <artifactId>shenyu-spring-boot-starter-plugin-rewrite</artifactId> <version>${last.version}</version> </dependency> <!-- shenyu rewrite plugin end-->
- 选择器配置请参考Apache ShenYu 网关选择器和规则解析
- 规则配置:
- rewriteURI: 重写后的uri
源码分析
rewrite插件的功能很简单,就是将服务选择器和规则配置的请求的uri替换为我们配置的 rewriteURI。核心源码如下:
public class RewritePlugin extends AbstractShenyuPlugin {
@Override
protected Mono<Void> doExecute(final ServerWebExchange exchange, final ShenyuPluginChain chain, final SelectorData selector, final RuleData rule) {
……
//将rewriteURI放到 web上下文的 属性中
exchange.getAttributes().put(Constants.REWRITE_URI, rewriteHandle.getRewriteURI());
return chain.execute(exchange);
}
}
contextpath
contextpath插件提供网关重写请求路径的contextPath的功能
插件应用
-
shenyu-admin -> 插件管理 -> contextPath编辑 -> 开启插件
-
shenyu-bootstrap 添加相关依赖,并重启
<!-- shenyu context_path plugin start--> <dependency> <groupId>org.apache.shenyu</groupId> <artifactId>shenyu-spring-boot-starter-plugin-context-path</artifactId> <version>${last.version}</version> </dependency> <!-- shenyu context_path plugin end-->
-
选择器配置请参考Apache ShenYu 网关选择器和规则解析
-
规则配置:
- contextPath: 根据请求的Url截取自定义的contextPath获取真正的Url,例如请求路径为/shenyu/http/order, 配置的contextPath为’/shenyu/http’,那么真正请求的url为’/order’。
源码分析
当请求匹配到选择器和规则信息后,根据请求的Url截取自定义的contextPath获取真正的url,并替换为真正的url。核心源码:
public class ContextPathMappingPlugin extends AbstractShenyuPlugin {
@Override
protected Mono<Void> doExecute(final ServerWebExchange exchange, final ShenyuPluginChain chain, final SelectorData selector, final RuleData rule) {
……
//处理context
this.buildContextPath(shenyuContext, contextMappingHandle);
return chain.execute(exchange);
}
private void buildContextPath(final ShenyuContext context, final ContextMappingHandle handle) {
//handle.getRealUrl()是什么?页面配置规则的时候只有contextPath
context.setContextPath(handle.getContextPath());
if (!StringUtils.isBlank(handle.getRealUrl())) {
log.info("context path mappingPlugin replaced old :{} , real:{}", context.getRealUrl(), handle.getRealUrl());
context.setRealUrl(handle.getRealUrl());
return;
}
……
}
}
从源码得知会从我们配置的realUrl中取真是的url,但是我们ontextPath页面规则配置只有配置一个contextPath参数。这是比较疑惑的地方。