spring-cloud中zuul自定义service级别,api级别的路由白名单
主要实现对在白名单中的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
可以被路由处理。
这样就实现了多维度的白名单路由处理。
如有不足,请不吝赐教。