通过过滤器向Request请求添加自定义标头

时间:2018-01-13 13:23:11

标签: spring servlets filter header request

我有一个扩展block类的类,它看起来像:

*block

问题是我可以向Filter添加自定义@Component @Order(Ordered.HIGHEST_PRECEDENCE) public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { System.out.println("--------------------------------------"); HttpServletRequest request = (HttpServletRequest) req; req.setAttribute("test", "test"); final HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type"); response.setHeader("Access-Control-Max-Age", "3600"); if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } 吗?我浏览了headerrequest中可用的所有方法,但找不到任何方法。但是在request模式下,我发现req内部是debug的列表。如何添加我的自定义CoyoteRequest

enter image description here

6 个答案:

答案 0 :(得分:2)

您无法在HttpServletRequest对象中设置标题,但可以使用包装类。

请参阅本指南:http://wilddiary.com/adding-custom-headers-java-httpservletrequest/

答案 1 :(得分:1)

我遵循了 Guy Smorodinsky 的回答,它对我有用,但我不得不向 MutableHttpServletRequest 添加另一个方法:

    @Override
    public Enumeration<String> getHeaders(String name) {
        Set<String> set = new HashSet<>();
        Optional.ofNullable(customHeaders.get(name)).ifPresent(h -> set.add(h));
        Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaders(name);
        while (e.hasMoreElements()) {
            // add the names of the request headers into the list
            String n = e.nextElement();
            set.add(n);
        }
        Optional.ofNullable(customHeaders.get(name)).ifPresent(h -> set.add(h));
        return Collections.enumeration(set);
    }

答案 2 :(得分:0)

Guy Smorodinsky的答案还可以,但是例如对于Spring,您可能想覆盖一些其他方法,例如Enumeration<String> getHeaders(String name),因为Spring在获取带有@RequestHeader批注的标头值时会使用此方法。

示例代码可能如下所示:

  @Override
  public Enumeration<String> getHeaders(String name) {
    Set<String> headerValues = new HashSet<>();
    headerValues.add(this.headers.get(name));

    Enumeration<String> underlyingHeaderValues = ((HttpServletRequest) getRequest()).getHeaders(name);
    while (underlyingHeaderValues.hasMoreElements()) {
      headerValues.add(underlyingHeaderValues.nextElement());
    }

    return Collections.enumeration(headerValues);
  }

答案 3 :(得分:0)

示例如何在春季通过过滤器将OAuth2Authentication的值中的用户名设置为自定义标头X-Login,并在控制器中将其用作参数@RequestHeader(X_LOGIN) String login

import static java.util.Collections.enumeration;
import static java.util.Collections.singleton;

@Component
public class HeaderLoginFilter extends GenericFilterBean {

    public static final String X_LOGIN = "X-Login";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        OAuth2Authentication auth = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
        if (auth.getUserAuthentication() == null) {
            //ignore, header value is set in my case 
            chain.doFilter(request, response);
            return;
        }

        //filling custom header with value from auth
        HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper((HttpServletRequest) request) {
            @Override
            public Enumeration<String> getHeaders(String name) {
                if (X_CLIENT_LOGIN.equals(name))
                    return enumeration(singleton(auth
                            .getUserAuthentication()
                            .getName()));
                return super.getHeaders(name);
            }
        };
        chain.doFilter(wrapper, response);
    }

}

答案 4 :(得分:0)

我在实现REST Client with Quarkus时遇到类似的问题,ClientRequestFilter对此问题进行了解决

@Provider
public class AddAuthHeadersRequestFilter implements ClientRequestFilter {
    private static final Logger LOG = Logger.getLogger(AddAuthHeadersRequestFilter.class);

    @Override
    public void filter(ClientRequestContext context) throws IOException {
        context.getHeaders().add("Authorization", "Bearer XXXXXXXXXXX");
    }
}

答案 5 :(得分:0)

如果出于任何原因添加新的过滤器或拦截器不是一种选择,反射和丑陋的代码是可以的。您可以执行以下操作以在控制器方法的主体中以编程方式修改现有标头:

<块引用>

警告!这很丑陋,绝对不应该在生产中使用!

private void modifyHeaders(HttpServletRequest request, String headerToFind, String valueToReplace) {
    Field field = request.getHeaderNames().getClass().getDeclaredField("val$names");
    field.setAccessible(true);
    Field field2 = field.get(request.getHeaderNames()).getClass().getDeclaredField("headers");
    field2.setAccessible(true);
    Field field3 = field2.get(field.get(request.getHeaderNames())).getClass().getDeclaredField("headers");
    field3.setAccessible(true);

    Object objects = field3.get(field2.get(field.get(request.getHeaderNames())));
    
    List array = new ArrayList();

    int length = Array.getLength(objects);
    for (int i = 0; i < length; i++) {
        array.add(Array.get(objects, i));
    }

    for (Object obj : array.toArray()) {
        field = obj.getClass().getDeclaredField("nameB");
        field.setAccessible(true);

        Object headerKey = field.get(obj);

        if (headerKey.toString().equalsIgnoreCase(headerToFind)) {
            field = obj.getClass().getDeclaredField("valueB");
            field.setAccessible(true);

            MessageBytes messageBytes = MessageBytes.newInstance();
            messageBytes.setString(valueToReplace));

            field.set(obj, messageBytes);

            break;
        }
    }
}