主要实现对在白名单中的service级别或者api级别的网关路由。
一.service和api级别的路由
1.service级别的网关路由
public class ServiceIdWhiteTableRouteLocator extends DiscoveryClientRouteLocator {
...
//主要重写该方法,在调用完super的locateRoutes后再与白名单列表比较,提取出交集
@Override
protected LinkedHashMap locateRoutes() {
LinkedHashMap routeMaps = super.locateRoutes();
LinkedHashMap whiteRouteMaps = new LinkedHashMap<>();
routeMaps.forEach((k, v) -> {
if (PatternMatchUtils.simpleMatch(whites, v.getServiceId())) {
whiteRouteMaps.put(k, v);
}
});
for (ZuulProperties.ZuulRoute route : this.properties.getRoutes().values()) {
whiteRouteMaps.put(route.getPath(), route);
}
return whiteRouteMaps;
}
...
}
2.api级别的网关路由
public class PathWhiteTableHandleMapping extends ZuulHandlerMapping {
...
//主要重写该方法,在原有的ZuulHandlerMapping基础上添加判断是否在白名单的逻辑
@Override
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
if (this.errorController != null && urlPath.equals(this.errorController.getErrorPath())) {
return null;
}
if (isIgnoredPath(urlPath, this.routeLocator.getIgnoredPaths())) return null;
/**
* 检查是否在白名单中,不在白名单中的不路由
*/
if (!isInPathWhiteTables(urlPath, this.pathWhites)) return null;
RequestContext ctx = RequestContext.getCurrentContext();
if (ctx.containsKey("forward.to")) {
return null;
}
if (this.dirty) {
synchronized (this) {
if (this.dirty) {
registerHandlers();
this.dirty = false;
}
}
}
return super.lookupHandler(urlPath, request);
}
private boolean isInPathWhiteTables(String urlPath, Collection pathWhites) {
for (String whitePath : pathWhites) {
if (this.pathMatcher.match(whitePath, urlPath)) {
return true;
}
}
return false;
}
public void setPathWhiteTables(Collection whites) {
this.pathWhites = whites;
}
...
}
二.config配置
1.首先卸载zuul自带的auto config.
@SpringBootApplication(exclude = ZuulProxyAutoConfiguration.class)
2.需要全量copy三个类
org.springframework.cloud.netflix.zuul.RibbonCommandFactoryConfiguration
org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration
org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration
然后修改ZuulServerAutoConfiguration
中的zuulHandlerMapping的bean注册:
@Bean(value = "discoveryRouteLocator")
public DiscoveryClientRouteLocator discoveryClientRouteLocator(ServerProperties server, DiscoveryClient discovery) {
//service白名单注入点
return new ServiceIdWhiteTableRouteLocator(server.getServlet().getServletPrefix(), discovery, this.zuulProperties, whiteRouteProperties.getWhiteServices());
}
@Bean(value = "zuulHandlerMapping")
public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes) {
PathWhiteTableHandleMapping mapping = new PathWhiteTableHandleMapping(routes, zuulController());
mapping.setErrorController(this.errorController);
//路径白名单注入点
mapping.setPathWhiteTables(whiteRouteProperties.getWhitePaths());
return mapping;
}
其中WhiteRouteProperties是一个装载配置属性的属性类,自己定义即可。ZuulProxyAutoConfiguration
需要修改其父类为上述的ZuulServerAutoConfigurationn
。
三. 配置文件配置
主要是在application.yaml文件中增加:
zuul:
#控制service级别白名单(list)
white-services:
- 'hello-server'
#控制api级别白名单(list)
white-paths:
- '/hello/world'
routes:
- url: hello-server
path: /hello/**
#默认全部不路由
ignored-services: '*'
上述配置可以实现将/hello/**
该pattern请求路由到hello-server上,由于默认设置全部不路由,通过zuul.routes加进去(看源码实现),然后由于设置了白名单功能,需要在white-services
上加上hello-server
,而white-paths
主要是控制白名单中的某个service中具体的哪个api可以被路由,如上可知是仅有/hello/world
可以被路由处理。
这样就实现了多维度的白名单路由处理。
如有不足,请不吝赐教。