Заголовок в ответе не должен быть подстановочным знаком"*", когда режим учетных данных запроса "include"

я использую Auth0 для моей аутентификации пользователя, чтобы разрешить только зарегистрированным пользователям доступ к Spring (Boot) RestController. На данный момент я создаю функциональность сообщений в реальном времени, где пользователи могут отправлять сообщения из Angular 2 клиент (localhost:4200) на сервер Spring (localhost: 8081) с помощью stompjs и sockjs.

при попытке создать Stomp-клиент и запуске соединения я получаю следующую консольную ошибку:

 The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

после исследования этого проблема похоже, что невозможно установить параметр origins = * и учетные данные = true одновременно. Как я могу это решить, когда я уже установил разрешенный источник в WebSocketConfig в клиентский домен?

угловой компонент 2

connect() {
    var socket = new SockJS('http://localhost:8081/chat');
    this.stompClient = Stomp.over(socket);  
    this.stompClient.connect({}, function(result) {
        console.log('Connected: ' + result);
        this.stompClient.subscribe('/topic/messages', function(message) {
            console.log(message);
        });
    });
}    

WebSocketConfig

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/chat").setAllowedOrigins("http://localhost:4200").withSockJS();
    }
}

на localhost:8081/чат/информация?t=1490866768565

{"entropy":-1720701276,"origins":["*:*"],"cookie_needed":true,"websocket":true}

MessageController

public class MessageController {
    @MessageMapping("/chat")
    @SendTo("/topic/messages")
    public Message send(Message message) throws Exception {
        return new Message(message.getFrom(), message.getText());
    }
}

SecurityConfig (временно разрешает все)

public class SecurityConfig extends Auth0SecurityConfig {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().permitAll();
    }
}

обновление

после еще нескольких испытаний и исследований кажется, что проблема возникает только с использованием Chrome. Проблема может быть связана с: https://github.com/sockjs/sockjs-node/issues/177

обновление

Я создал CORSFilter как упомянутый chsdk и использовал метод addFilterBefore() : https://stackoverflow.com/a/40300363/4836952.

@Bean
CORSFilter corsFilter() {
    CORSFilter filter = new CORSFilter();
    return filter;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(corsFilter(), SessionManagementFilter.class).authorizeRequests().anyRequest().permitAll();
    http.csrf().disable();
}

Я вижу, что фильтр вызывается отладкой, но сообщение об ошибке продолжает появляться на стороне клиента, даже если установлен правильный Access-Control-Allow-Origin:

enter image description here

4 ответов


:

вы не настраиваете 'Access-Control-Allow-Origin' правильно, и ваша текущая конфигурация просто игнорируется сервером.

ситуация:

трассировка стека ошибок говорит:

значение 'Access-Control-Allow-Origin' заголовок в ответе не должен быть подстановочным знаком '*' когда режим учетных данных запроса "include". Происхождение'http://localhost:4200 ' поэтому не допускается доступ.

это означает, что помимо того, что вы не можете установить 'Access-Control-Allow-Origin' к шаблону "*" ваш домен 'http://localhost:4200' также не разрешен доступ.

чтобы ответить на ваш вопрос:

как я могу это решить, когда я уже установил разрешенный источник в WebSocketConfig в клиентский домен?

устранение:

Я думаю, вам не нужно устанавливать разрешенное происхождение в WebSocketConfig потому что он предназначен для настройки WebSocket-стиль обмена сообщениями в веб-приложениях как говорится в Поддержка WebSocket весной документации, вам нужно будет настроить его в CORSFilter класс конфигурации, поскольку он предназначен для настройки фильтров Spring для доступа к веб-приложению.

это то, что вам нужно в вашей CORSFilter.java класса конфигурации:

public class CORSFilter implements Filter {

    // This is to be replaced with a list of domains allowed to access the server
  //You can include more than one origin here
    private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200"); 

    public void destroy() {

    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        // Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects)
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;

            // Access-Control-Allow-Origin
            String origin = request.getHeader("Origin");
            response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "");
            response.setHeader("Vary", "Origin");

            // Access-Control-Max-Age
            response.setHeader("Access-Control-Max-Age", "3600");

            // Access-Control-Allow-Credentials
            response.setHeader("Access-Control-Allow-Credentials", "true");

            // Access-Control-Allow-Methods
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");

            // Access-Control-Allow-Headers
            response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, " + "X-CSRF-TOKEN");
        }

        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {
    }
}

вы можете увидеть использование :

private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200");

установить список доменов, которым разрешен доступ к серверу.

ссылки:

возможно, вам придется взглянуть на поддержка CORS в Spring Framework и включение перекрестных запросов происхождения для веб-службы RESTful для дальнейшего чтения об этом.


это не имеет ничего общего с вашим кодом приложения spring или angular.

вступление к вашей проблеме
The Управление Доступом-Разрешить-Origin является частью CORS (Совместное Использование Ресурсов Cross-Origin) механизм, который дает веб-серверам управление доступом через домен. Он предназначен для защиты вашего приложения / сайта от CSRF (Подделка Межсайтовых Запросов).

CORS / CSRF

проблема
Теперь, если мы внимательно прочитаем вашу ошибку

The value of the 'Access-Control-Allow-Origin' header in the response must 
not be the wildcard '*' when the request's credentials mode is 'include'. 
Origin 'http://localhost:4200' is therefore not allowed access.

Он говорит, что Управление Доступом-Разрешить-Origin заголовок не может быть подстановочным знаком.

другими словами, Теперь ваш сервер говорит, что все со всего интернета могут запускать код на моем сайте.

чего мы хотим достичь: ограничьте происхождение только вашим приложением переднего плана (ng2).

решение Теперь, поскольку вы используете Spring, я предположу, что вы используете его с Apache Tomcat в качестве своего веб-сервера.

CORS различаются как фильтр в вашем интернете.conf (папка tomcat)

найти строку

<init-param>
  <param-name>cors.allowed.origins</param-name>
  <param-value>*</param-value>
</init-param>

и измените * на http://localhost:4200

для получения дополнительной информации о конфигурации CORS в Tomcat пожалуйста, прочитайте этот

редактировать (Весенний ботинок)
Поскольку вы используете spring boot, вы можете делегировать конфигурацию cors платформе.

пожалуйста этот учебник по весне.Ио (как предложил chsdk), чтобы лучше понять конфигурацию CORS с spring boot .


мой ответ слишком поздно, но я публикую это, если кто-то может столкнуться с той же проблемой, я столкнулся с той же проблемой перекрестного происхождения.

В основном, если вы используете Spring Security, реализованную на вашем серверном приложении, вероятно, это он блокирует WebSocket handshaker

вы должны сказать Spring security, чтобы разрешить конечные точки websocket, чтобы разрешить рукопожатие сокета... используя

.antMatchers("/socket/**").permitAll()

Так sockjs будет теперь можно отправить запрос GET (Http) для рукопожатия перед переключением на протокол Websocket

это конфигурация безопасности Spring

package org.souhaib.caremy.security.module.config;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint).and()
            .authorizeRequests()
            .antMatchers(SecurityParams.PUBLIC_ROUTES).permitAll()
            .antMatchers("/socket/**").permitAll();

    http.csrf().disable();
}}

это конфигурация брокера WebSocket

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/socket")
                .setAllowedOrigins("http://localhost:4200")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app")
                .enableSimpleBroker("/chat");
    }
}

просто добавить .setAllowedOrigins("*") в конфигурации webSocket.

@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
    stompEndpointRegistry.addEndpoint("/yourEndpoint");
    stompEndpointRegistry.addEndpoint("/yourEndpoint").setAllowedOrigins("*").withSockJS();
}

версия webSocket-1.4.1.RELEASE, вы должны обновить свою версию, если метод не был показан.