已有Zuul服务路由,如何通过Spring Cloud Gateway实现白名单域名过滤?
解决方案:域名白名单过滤实现
不管是Spring Cloud Gateway还是你当前使用的Zuul,都可以实现域名白名单过滤需求,以下是两种具体方案:
方案一:Spring Cloud Gateway 实现方式
你可以通过自定义GatewayFilterFactory来实现域名白名单校验,步骤如下:
1. 自定义网关过滤器工厂
创建一个过滤器工厂类,读取配置的白名单域名,校验请求的Origin或Referer头是否在白名单内:
import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import java.util.List; @Component public class DomainWhitelistGatewayFilterFactory extends AbstractGatewayFilterFactory<DomainWhitelistGatewayFilterFactory.Config> { public DomainWhitelistGatewayFilterFactory() { super(Config.class); } @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { // 获取请求头中的Origin或Referer String origin = exchange.getRequest().getHeaders().getFirst("Origin"); String referer = exchange.getRequest().getHeaders().getFirst("Referer"); String requestDomain = null; // 优先取Origin,没有则取Referer if (origin != null) { requestDomain = extractDomain(origin); } else if (referer != null) { requestDomain = extractDomain(referer); } // 校验域名是否在白名单内 if (requestDomain == null || !config.getAllowedDomains().contains(requestDomain)) { exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); return exchange.getResponse().setComplete(); } return chain.filter(exchange); }; } // 从URL中提取域名(去掉协议、端口、路径等) private String extractDomain(String url) { return url.replaceAll("^https?://(www\\.)?|(:\\d+).*$", ""); } public static class Config { private List<String> allowedDomains; public List<String> getAllowedDomains() { return allowedDomains; } public void setAllowedDomains(List<String> allowedDomains) { this.allowedDomains = allowedDomains; } } }
2. 配置路由与白名单
在application.yml中配置路由,并应用该过滤器,指定允许的域名:
spring: cloud: gateway: routes: - id: your-service-route uri: lb://your-service predicates: - Path=/api/** filters: - name: DomainWhitelist args: allowedDomains: - example.com - trusted-domain.com
方案二:现有Zuul 改造实现
如果你不想替换Zuul,可以通过自定义Zuul过滤器来实现相同逻辑:
1. 自定义Zuul过滤器
创建一个前置过滤器(pre类型),在请求路由前校验域名:
import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.util.List; @Component public class DomainWhitelistZuulFilter extends ZuulFilter { @Value("${zuul.domain.allowed-list}") private List<String> allowedDomains; @Override public String filterType() { return "pre"; // 前置过滤器,在路由前执行 } @Override public int filterOrder() { return 1; // 执行顺序,数字越小越先执行 } @Override public boolean shouldFilter() { return true; // 是否启用该过滤器 } @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); // 获取请求头中的Origin或Referer String origin = request.getHeader("Origin"); String referer = request.getHeader("Referer"); String requestDomain = null; if (origin != null) { requestDomain = extractDomain(origin); } else if (referer != null) { requestDomain = extractDomain(referer); } // 校验域名 if (requestDomain == null || !allowedDomains.contains(requestDomain)) { ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(HttpStatus.FORBIDDEN.value()); ctx.setResponseBody("Forbidden: Request domain is not allowed"); } return null; } private String extractDomain(String url) { return url.replaceAll("^https?://(www\\.)?|(:\\d+).*$", ""); } }
2. 配置白名单
在application.yml中添加白名单配置:
zuul: domain: allowed-list: example.com,trusted-domain.com
注意事项
- 可以根据业务需求调整域名提取逻辑,比如是否保留
www前缀、是否需要匹配子域名等 - 对于没有
Origin和Referer头的请求(比如直接API调用),可以根据需求选择允许或拦截,可在过滤器中添加自定义逻辑处理 - 白名单建议配置在配置中心,方便动态修改
内容的提问来源于stack exchange,提问作者Shivam Singh
相关产品推荐
相关产品推荐

