2017-10-03 8 views
0

Nginxリバースプロキシの後ろにSpringブートサーバーがあり、Reactアプリケーションからフェッチを使用してアクセスします。フロントエンドは別のポートから提供されるので、サーバー上でCORSを有効にする必要があります。ほとんどの場合、これはうまくいきますが、OPTIONSのプリフライトリクエストに応じて約1%のユーザーが403を受け取っています。その理由を理解するためには助けが必要です。私が持っている最大の問題は、自分のマシンで問題を再現することができないということです。POSTプリフライト時(時々)

スプリングブートCORSの設定:

@Bean 
public FilterRegistrationBean corsFilter() { 
    CorsConfiguration config = new CorsConfiguration(); 
    config.addAllowedOrigin("https://example.com"); 
    config.addAllowedHeader("*"); 
    config.addAllowedMethod("GET"); 
    config.addAllowedMethod("PUT"); 
    config.addAllowedMethod("POST"); 
    config.addAllowedMethod("DELETE"); 
    config.addAllowedMethod("PATCH"); 

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 
    source.registerCorsConfiguration("/**", config); 

    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); 
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE); 
    return bean; 
} 

nginxの設定ファイル(3000フロントエンドおよび3001をサービングNodeJS春ブートされる):

server { 
    ... 

    location/{ 
     proxy_pass http://localhost:3000; 
     proxy_http_version 1.1; 
     proxy_set_header Upgrade $http_upgrade; 
     proxy_set_header Connection 'upgrade'; 
     proxy_set_header Host $host; 
     proxy_cache_bypass $http_upgrade; 
    } 

    location /api/v1/ { 
     proxy_pass http://localhost:3001; 
     proxy_http_version 1.1; 
     proxy_set_header Upgrade $http_upgrade; 
     proxy_set_header Connection 'upgrade'; 
     proxy_set_header Host $host; 
     proxy_cache_bypass $http_upgrade; 
    } 

    ... 
} 

nginxのログフォーマット(Iは、明確にするため一部を除去):

"$request" $status "$http_referer" "$http_user_agent" 

Nginx access.logを見ると、2種類のログ行wh ERE 403のショー:

"OPTIONS /api/v1/oauth/token?grant_type=password&username=user%40example.com&password=****" 403 "https://www.example.com/login" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36" 

意味Windows 7を実行しているクロム61、および

"OPTIONS /api/v1/oauth/token?grant_type=password&username=user%40example.com&password=****" 403 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko" 

意味Windows 7のIE11を実行しています。

同じ設定のOSとブラウザを使用している他のユーザーは、問題はありません。手動フェッチと共に送信

データ:(クロームコンソールから)作業ユーザのプリフライト要求に

URL: https://example.com:3001/api/v1/oauth/token?grant_type=password&username=user%40example.com&password=**** 
Method: POST 
Headers: 
    Authorization: Basic XXXXXXXXXXX= 
    Content-Type: application/x-www-form-urlencoded 
Body: undefined 

実パラメータ:

要求ヘッダー:

OPTIONS /api/v1/oauth/token?grant_type=password&username=user%40example.com&password=**** HTTP/1.1 
Host: https://example.com:3001 
Connection: keep-alive 
Access-Control-Request-Method: POST 
Origin: https://example.com:3000 
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 
Access-Control-Request-Headers: authorization 
Accept: */* 
Referer: https://example.com:3000/login 
Accept-Encoding: gzip, deflate 
Accept-Language: en-US,en;q=0.8,sv;q=0.6 

応答ヘッダー:

HTTP/1.1 200 
Access-Control-Allow-Origin: https://example.com:3000 
Vary: Origin 
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,PATCH 
Access-Control-Allow-Headers: authorization 
Content-Length: 0 
Date: Tue, 03 Oct 2017 16:01:37 GMT 

フェッチ要求を送信する方法に問題があるか、ヘッダーが正しく構成されていない可能性があります。しかし、これまで私はそれを解決することができませんでした。

助けがあれば幸いです。

答えて

0

私は最終的にエラーを見つけることができました。それは完全に自分自身の責任でした。

Nginx access.logに見られるように、失敗したプリフライトの1つは$http_referer、つまりオリジンヘッダーはwww.example.com/loginです。これは、私のCORS設定がサブドメインを持たないexample.com、がない場合にのみ、プリフライトに失敗します。

wwwサブドメインからのすべての要求が301 Permanently movedを使用して、非wwwドメインにリダイレクトを返すように私はnginxの設定ファイルにserverブロックを追加することによって、これを修正しました。また、私

server { 
    ... 

    listen 443 ssl; 

    server_name example.com; 

    location/{ 
      proxy_pass http://localhost:3000; 
      proxy_http_version 1.1; 
      proxy_set_header Upgrade $http_upgrade; 
      proxy_set_header Connection 'upgrade'; 
      proxy_set_header Host $host; 
      proxy_cache_bypass $http_upgrade; 
    } 

    location /api/v1/ { 
      proxy_pass http://localhost:3001; 
      proxy_http_version 1.1; 
      proxy_set_header Upgrade $http_upgrade; 
      proxy_set_header Connection 'upgrade'; 
      proxy_set_header Host $host; 
      proxy_cache_bypass $http_upgrade; 
    } 

    ... 
} 

server { 
    server_name www.example.com example.com; 

    return 301 https://example.com$request_uri; 
} 

server { 
    listen 443 ssl; 

    server_name www.example.com; 

    return 301 https://example.com$request_uri; 
} 

注意すべての暗号化を維持するために、すべてのhttpトラフィックをhttpsにリダイレクトします。

このようにして、https://example.comを使用して2つのサーバにすべてのリクエストが入力されていることを確認できます。CORS設定を変更する必要はありません。