zuul忽略来自客户端的标头,但允许zuul过滤器addZuulRequestHeader

时间:2019-10-19 05:10:10

标签: spring-boot netflix-zuul

如何忽略客户端(原始请求)的标头,例如user-id,但是在过滤器中,我从oauth设置了用户ID,并由addZuulRequestHeader("user-id", "value")设置了用户ID,然后是微服务将使用。

我使用ignore-headers,那么即使我通过zuul过滤器设置了标头,它也会忽略所有内容。如何仅忽略客户端请求中的标头,却允许zuul添加它?

2 个答案:

答案 0 :(得分:0)

您可以实现以下过滤器:

@Component
public class MyHeaderFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        final RequestContext context = RequestContext.getCurrentContext();
        context.addZuulRequestHeader("user-id", "whateverValue");
        return null;
    }
}

您可以如上所述替换标头值。

答案 1 :(得分:0)

我亲自研究了一下,得出的结论是,唯一好的方法是包装HttpServletRequest,以使禁止的标头不会在HttpServletRequest::getHeaderNames调用中返回。 ProxyRequestHelper对原始请求标头和使用RequestContext.getCurrentContext().addZuulRequestHeader(headerName, headerValue)设置的标头都使用了忽略的标头集,因此,您不能只使用忽略的标头集。

您可以在各种路由过滤器中覆盖ProxyRequestHelper或执行以下操作:创建包装器(确保forbiddenHeaders的值被修剪和小写):

public class ForbiddenHeadersRequestWrapperEnforcer extends HttpServletRequestWrapper
{
    private Set<String> forbiddenHeaders;

    public ForbiddenHeadersRequestWrapperEnforcer(HttpServletRequest request, Set<String> forbiddenHeaders)
    {
        super(request);
        this.forbiddenHeaders = forbiddenHeaders;
    }

    @Override
    public Enumeration<String> getHeaderNames()
    {
        Set<String> headerNames = enumerationToLowercaseSet(super.getHeaderNames());
        headerNames.removeAll(forbiddenHeaders);
        return Collections.enumeration(headerNames);
    }

    private Set<String> enumerationToLowercaseSet(Enumeration<String> enumeration)
    {
        Set<String> set = new HashSet<>();
        while (enumeration.hasMoreElements()) {
            set.add(enumeration.nextElement().toLowerCase());
        }
        return set;
    }
}

一个简单的属性类:

@Component
@ConfigurationProperties("zuul")
public class ForbiddenHeadersProperties
{
    private List<String> forbiddenHeaders;

    public List<String> getForbiddenHeaders()
    {
        return forbiddenHeaders;
    }

    public void setForbiddenHeaders(List<String> forbiddenHeaders)
    {
        this.forbiddenHeaders = forbiddenHeaders;
    }
}

并在Zuul过滤器中使用该包装器:

@Component
public class ForbiddenHeaderEnforcerRouteFilter extends ZuulFilter
{
    private Set<String> forbiddenHeaders;

    public ForbiddenHeaderEnforcerRouteFilter(ForbiddenHeadersProperties forbiddenHeadersConfiguration)
    {
        this.forbiddenHeaders = forbiddenHeadersConfiguration.getForbiddenHeaders()
                                                             .stream()
                                                             .map(String::toLowerCase)
                                                             .map(String::trim)
                                                             .collect(Collectors.toSet());
    }

    @Override
    public int filterOrder()
    {
        return Integer.MIN_VALUE;
    }

    @Override
    public String filterType()
    {
        return FilterConstants.ROUTE_TYPE;
    }

    @Override
    public boolean shouldFilter()
    {
        return true;
    }

    @Override
    public Object run() throws ZuulException
    {
        RequestContext currentContext = RequestContext.getCurrentContext();
        currentContext.setRequest(new ForbiddenHeadersRequestWrapperEnforcer(currentContext.getRequest(),
                                                                             forbiddenHeaders));
        return null;
    }
}

这样,您可以使用RequestContext.getCurrentContext().addZuulRequestHeader(headerName, headerValue)设置标头,这些标头将发送到后端,但不会发送到原始请求中的标头。