web-dev-qa-db-fra.com

Ajout d'un en-tête personnalisé à la demande via le filtre

J'ai une classe qui étend la classe Filter et elle ressemble à:

@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);
        }
    }

La question est de savoir si je peux ajouter un header personnalisé à request? J'ai parcouru toutes les méthodes disponibles dans request et req et je n'ai trouvé aucun moyen. Mais en mode debug, j'ai trouvé qu'à l'intérieur de CoyoteRequest se trouve la liste de headers. Comment puis-je y ajouter mon header personnalisé?

enter image description here

6
Jan Testowy

Vous ne pouvez pas définir les en-têtes dans HttpServletRequestobject, mais vous pouvez utiliser une classe wrapper.

Regardez ce guide: http://wilddiary.com/adding-custom-headers-Java-httpservletrequest/


Juste au cas où pour l'avenir le lien deviendrait invalide:

final class MutableHttpServletRequest extends HttpServletRequestWrapper {
    // holds custom header and value mapping
    private final Map<String, String> customHeaders;

    public MutableHttpServletRequest(HttpServletRequest request){
        super(request);
        this.customHeaders = new HashMap<String, String>();
    }

    public void putHeader(String name, String value){
        this.customHeaders.put(name, value);
    }

    public String getHeader(String name) {
        // check the custom headers first
        String headerValue = customHeaders.get(name);

        if (headerValue != null){
            return headerValue;
        }
        // else return from into the original wrapped object
        return ((HttpServletRequest) getRequest()).getHeader(name);
    }

    public Enumeration<String> getHeaderNames() {
        // create a set of the custom header names
        Set<String> set = new HashSet<String>(customHeaders.keySet());

        // now add the headers from the wrapped request object
        @SuppressWarnings("unchecked")
        Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
        while (e.hasMoreElements()) {
            // add the names of the request headers into the list
            String n = e.nextElement();
            set.add(n);
        }

        // create an enumeration from the set and return
        return Collections.enumeration(set);
    }
}

utilisation:

@Override
public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(req);
    ...
    mutableRequest.putHeader("x-custom-header", "custom value");
    chain.doFilter(mutableRequest, response);
}
7
Guy Smorodinsky

La réponse de Guy Smorodinsky est correcte, mais par exemple pour Spring, vous voudrez peut-être remplacer certaines méthodes supplémentaires, comme Enumeration<String> getHeaders(String name), car Spring l'utilise tout en obtenant la valeur d'en-tête avec @RequestHeader annotation.

Un exemple de code peut ressembler à ceci:

  @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);
  }
0
Jakub Kvba

Exemple comment vous pouvez définir un nom d'utilisateur à partir de la valeur d'OAuth2Authentication sur l'en-tête personnalisé X-Login via un filtre au printemps et l'utiliser dans le contrôleur comme l'un des arguments @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);
    }

}
0
Vladimir Lykov