web-dev-qa-db-ja.com

要求の資格情報モードが「include」の場合、応答のヘッダーはワイルドカード「*」であってはなりません

ユーザー認証にAuth0を使用して、ログインしているユーザーのみがSpring(ブート)RestControllerにアクセスできるようにします。この時点で、ユーザーがstompjssockjsを使用してAngular 2クライアント(localhost:4200)からSpringサーバー(localhost:8081)にメッセージを送信できるリアルタイムメッセージ機能を作成しています。

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で許可されたOriginをクライアントドメインに既に設定している場合、これをどのように解決できますか?

Angular 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/chat/info?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();
    }
}

UPDATE

さらにテストと調査を行った結果、問題はChromeを使用した場合にのみ発生するようです。問題は以下に関連している可能性があります: https://github.com/sockjs/sockjs-node/issues/177

UPDATE

前述のchsdkのようなCORSFilterを作成し、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

29
Sam

問題:

'Access-Control-Allow-Origin'を正しく設定しておらず、現在の設定はサーバーによって単に無視されます。

状況:

エラースタックトレースには次のように表示されます。

リクエストのクレデンシャルモードが「include」の場合、応答の'Access-Control-Allow-Origin'ヘッダーの値はワイルドカード'*'であってはなりません。したがって、オリジン ' http:// localhost:42 'はアクセスを許可されていません。

つまり、'Access-Control-Allow-Origin'をワイルドカード"*"に設定できないという事実は別として、ドメイン'http://localhost:4200'もアクセスを許可されません。

質問に答えるには:

WebSocketConfigで許可されたOriginをクライアントドメインに既に設定している場合、これをどのように解決できますか?

解決策:

許可されるOriginをWebSocketConfigに設定する必要はないと思います。これは(WebアプリケーションでのWebSocketスタイルのメッセージングWebSocket Support(Springドキュメント 、Webアプリケーションアクセス用のSpring Filtersを構成するため、CORSFilter構成クラスで構成する必要があります。

これは、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");

サーバーへのアクセスが許可されているドメインのリストを設定します。

参照:

Spring Framework および RESTful Webサービスのクロスオリジンリクエストを有効にする .

16
cнŝdk

これは、スプリングやangularアプリコードとは関係ありません。

問題の紹介
Access-Control-Allow-OriginはCORSの一部です(Cross-Origin Resource Sharing) Webサーバーにクロスドメインアクセス制御を提供するメカニズム。 CSRF(Cross-Site Request Forgery)からアプリ/サイトを保護するために用意されています。

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.

Access-Control-Allow-Originヘッダーはワイルドカードにできません。

言い換えれば、今、あなたのバックエンドは、ウェブ上のすべての人が私のサイトでコードを実行できると言っています。

達成したいこと:Originをフロントエンドアプリ(ng2)のみに制限します。

SolutionSpringを使用しているため、Apache TomcatをバックエンドWebサーバーとして使用していると仮定します。

CORSはweb.conf(Tomcatフォルダー)のフィルターとして定義されています

この行を見つける

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

*を http:// localhost:42 に変更します

tomcatでのCORSの設定の詳細については これをお読みください

EDIT(Spring boot)
スプリングブートを使用しているため、corsの構成をフレームワークに委任できます。

spring.ioのこのチュートリアル (chsdk提案のように)に従って、spring bootでのCORS構成をよりよく把握してください。

6
VikingCode

私の答えは遅すぎますが、誰かが同じ問題に直面する可能性がある場合、私はこれを投稿しています、私は同じクロスオリジンの問題に直面しています。

基本的にサーバーサイドアプリケーションに実装されたSpring Securityを使用している場合、おそらくWebsocketハンドシェーカーをブロックするのは彼です

ソケットのハンドシェイクを許可するには、Websocketエンドポイントを許可するようSpringセキュリティに指示する必要があります... using

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

そのため、sockjsは、Websocketプロトコルに切り替える前に、ハンドシェイクのGET(Http)要求を送信できるようになります

これは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");
    }
}
2