Как добавить собственный заголовок в Spring WebFilter?

Я пытаюсь добавить собственный фильтр, прежде чем вызывать службу REST. В этом классе ниже я пытаюсь добавить настраиваемый фильтр в HttpRequest, но получаю сообщение об ошибке: -

java.lang.UnsupportedOperationException: null в java.util.Collections$UnmodifiableMap.computeIfAbsent(Collections.java:1535) ~[na:1.8.0_171] в org.springframework.util.CollectionUtils$MultiValueMapAdapter.add(CollectionUtils. java:459) ~[spring-core-5.0.7.RELEASE.jar:5.0.7.RELEASE]

public class AuthenticationWebFilter implements WebFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationWebFilter.class);

    @Autowired
    private TokenServiceRequest tokenServiceRequest;

    @Autowired
    private AuthenticationProvider authenticationProvider;

    public AuthenticationWebFilter(TokenServiceRequest tokenServiceRequest, AuthenticationProvider authenticationProvider) {
        super();
        this.tokenServiceRequest = tokenServiceRequest;
        this.authenticationProvider = authenticationProvider;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
        HttpHeaders requestHeaders = serverWebExchange.getRequest().getHeaders();
        HttpHeaders responseHeaders = serverWebExchange.getResponse().getHeaders();
        LOGGER.info("Response HEADERS: "+responseHeaders);
        LOGGER.info("Request HEADERS: "+serverWebExchange.getRequest().getHeaders());

        tokenServiceRequest.setUsername(serverWebExchange.getRequest().getHeaders().getFirst(CommerceConnectorConstants.USERNAME));
        tokenServiceRequest.setPassword(serverWebExchange.getRequest().getHeaders().getFirst(CommerceConnectorConstants.PASSWORD));
        tokenServiceRequest.setClientId(serverWebExchange.getRequest().getHeaders().getFirst(CommerceConnectorConstants.CLIENT_ID));
        tokenServiceRequest.setSecretClient(serverWebExchange.getRequest().getHeaders().getFirst(CommerceConnectorConstants.SECRET_CLIENT));
        LOGGER.info("Token Received: " + authenticationProvider.getUserAccessToken(tokenServiceRequest).getTokenId());

        //responseHeaders.set(CommerceConnectorConstants.X_AUTH_TOKEN, authenticationProvider.getUserAccessToken(tokenServiceRequest).getTokenId());
        //responseHeaders.add(CommerceConnectorConstants.X_AUTH_TOKEN, authenticationProvider.getUserAccessToken(tokenServiceRequest).getTokenId());

        //This below code is not working
        serverWebExchange.getRequest().getQueryParams().add("test", "value");

        //This below code is not working
        //serverWebExchange.getRequest().getHeaders().add(CommerceConnectorConstants.X_AUTH_TOKEN, authenticationProvider.getUserAccessToken(tokenServiceRequest).getTokenId());
        LOGGER.info("Exiting filter@AuthenticationWebFilter");
        return webFilterChain.filter(serverWebExchange);
    }
    }

В HTTPResponse я могу установить пользовательские заголовки, но мне нужно добавить пользовательский заголовок в HTTPRequest. Пожалуйста, порекомендуйте.


person Vinod Kumar    schedule 19.06.2018    source источник


Ответы (4)


Если вы используете облачный шлюз Spring, заголовок запроса может быть изменен с помощью реализации GlobalFilter или GatewayFilter.

    @Component 
    public class LogFilter implements GlobalFilter, Ordered {

    private Logger LOG = LoggerFactory.getLogger(LogFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        return chain.filter(
                exchange.mutate().request(
                        exchange.getRequest().mutate()
                                .header("customer-header", "customer-header-value")
                                .build())
                        .build());
    }

    @Override
    public int getOrder() {
        return 0;
    } }

Если вы находитесь в ZuulFilter, addZuulRequestHeader может изменить заголовок запроса.

    RequestContext.getCurrentContext().addZuulRequestHeader("customer-header", "customer-header-value");

Надеюсь, это полезно.

person Christian tom    schedule 16.07.2018
comment
Реализуя интерфейс WebFilter, вы можете сделать то же самое, что и реализацию GatewayFilter. - person Christian tom; 16.07.2018
comment
Как изменить ответ в весеннем облачном шлюзе? - person Minisha; 02.10.2018
comment
О, это здорово, я сэкономил часы, чтобы узнать, что вы можете изменить обмен и запрос. - person Stephan; 26.03.2019

Я думаю, что исключение выбрасывается из соображений безопасности. Было бы неприятно, если бы фильтр мог добавлять/изменять заголовки HTTP-запросов. Конечно, вы можете добиться этого, создав серию декораторов:

import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebExchangeDecorator;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

    public class CustomFilter implements WebFilter {

    public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {

            ServerWebExchangeDecorator decorator = new ServerWebExchangeDecoratorImpl(serverWebExchange);

            //do your stuff using decorator 

            return webFilterChain.filter(decorator);
        }
    }


    class ServerWebExchangeDecoratorImpl extends ServerWebExchangeDecorator {

        private ServerHttpRequestDecorator requestDecorator;

        public ServerWebExchangeDecoratorImpl(ServerWebExchange delegate) {
            super(delegate);
            this.requestDecorator = new ServerHttpRequestDecoratorImpl(delegate.getRequest());
        }

        @Override
        public ServerHttpRequest getRequest() {
            return requestDecorator;
        }

    }

    class ServerHttpRequestDecoratorImpl extends  ServerHttpRequestDecorator {

        // your own query params implementation
        private MultiValueMap queryParams;

        public ServerHttpRequestDecoratorImpl(ServerHttpRequest request) {
            super(request);
            this.queryParams = new HttpHeaders();
            this.queryParams.addAll(request.getQueryParams());
        }

        @Override
        public MultiValueMap<String, String> getQueryParams() {
            return queryParams;
        }

        //override other methods if you want to modify the behavior
    }
person Marcin Bukowiecki    schedule 19.06.2018
comment
хорошо, поняли, что мы не можем добавить/изменить HTTP-запрос, но можем ли мы добавить в него токен аутентификации Jwt? - person Vinod Kumar; 20.06.2018
comment
Да. Токен JWT можно добавить в виде стандартного шаблона: Authorization: Bearer <token>. Где Authorization — имя заголовка, а Bearer <token> — значение заголовка. - person Marcin Bukowiecki; 20.06.2018

У меня та же проблема, потому что заголовки уже имеют один и тот же ключ; Мое решение - установить ключ в заголовке, сначала проверить, существует ли ключ;

@Configuration
public class AuthGatewayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        Consumer<HttpHeaders> httpHeaders = httpHeader -> {
            // check exists
            if(StringUtils.isBlank(httpHeader.getFirst("xxx"))){
                httpHeader.add("xxx", "xxx");
            }
        };
        ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().headers(httpHeaders).build();
        exchange = exchange.mutate().request(serverHttpRequest).build();

        return chain.filter(exchange);
    }

}
person imfan    schedule 15.06.2021

person    schedule
comment
Можете ли вы предоставить некоторый контекст для своего ответа, а не просто код? - person David Buck; 20.11.2019
comment
Извините, это означает, что скопируйте исходный запрос и добавьте токен заголовка. Надеюсь, я смогу вам помочь. Мой английский оставляет желать лучшего. - person meng; 21.11.2019