Nuxt.jsでログインフォームが作りたい~CORSと戦ってみた~

HBソフトスタジオのみよしです。
先日Nuxt.jsでログインフォームを作成していて、とあるエラー文に散々苦しめられたので今回はそのお話をしたいと思います。

そのエラーとは

CORS header ‘Access-Control-Allow-Origin’ missing!!!

そう、CORS(Cross-Origin Resource Sharing)のお話です。

そもそもCORSって何?

Cross-Origin Resource Sharing の略、日本語訳すると「オリジン間リソース共有」です。
まずはオリジンについて確認しましょう。
オリジンとは「スキーム + ホスト + ポート番号」の事。
スキーム + ホスト + ポート番号
オリジンの「スキーム + ホスト + ポート番号」が一致している場合に両者は”同じオリジン”となります。

上記を踏まえて同一オリジンポリシー(Same Origin Policy)も理解しちゃいましょう。

同一オリジンポリシーは重要なセキュリティの仕組みであり、あるオリジンによって読み込まれた文書やスクリプトが、他のオリジンにあるリソースにアクセスできる方法を制限するものです。

(参考)同一オリジンポリシー – Web セキュリティ | MDN
つまり「異なるオリジン(クロスオリジン)からのリソースへのアクセスを制限しよう」ということ。
ということは異なるオリジンのリクエストはブロックされてしまいます。

クロスオリジン

※厳密には制限されるものとされないものがあるので、そこの所は参考ページを読んでみてください。

でも異なるオリジンのAPIを呼び出したい時にブロックされては困ってしまう…。
そんな時に使用するのがCORS(オリジン間リソース共有)です。
サーバーで「Access-Control-Allow-Origin」などのCORSヘッダーを定義し、どの通信を許可するかの設定を行っておけばリソースへのアクセスが許可されるという訳です。

CORS

さて、設定してみようか

つまりの所、レスポンスのヘッダーに”Access-Control-Allow-Origin”が設定されていればいいんだな。ふんふん…。


response = {
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type",
},
"body": json.dumps(status),
"isBase64Encoded": False
}

どやさ!

has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

なんっっでやねん!!!

そうです。そんな簡単な話なはずがないのです。

今回はNuxt/axiosを使用してAPIに接続を行っているため、axiosの機能を使ってproxyを行うのが現状で最も良い解決策のようです。


modules: [
  '@nuxtjs/proxy',
],
axios: {
  proxy: true
},
proxy: {
  '/api/': {
    target: 'https://example.com',
    pathRewrite: {'^/api/': '/'}
  },
},
auth: {
  local: {
    login: {
      url: '/api/login',
      method: 'post',
    },
  },
},

Amazon API Gatewayでの対応方法

さて、このログインフォームをAmazon S3にアップロードして完了だ!
と思ったのですが、そうは問屋が卸さないのです。
今度のエラーは405エラー。

POST http://example.s3-website-ap-northeast-1.amazonaws.com/api/login 405

ローカルで開発している間は問題なくAPI通信が出来たのですが、アップロードをしたところproxyが通っていないようでした。

そもそも今回Amazon API gatewayをLambdaのトリガーにしているのだから、CORSを有効設定を行えば良い話なのです。
Amazon API gatewayでは「CORSを有効」にする設定ができます。
場所はAmazon API gatewayのリソース内。メソッドを選択した状態でアクションボタンから選択しましょう。

API gateway

あとは、Access-Control-Allow-HeadersやAccess-Control-Allow-Originを設定して[CORS を有効にして既存の CORS ヘッダーを置換] を選択します。
Access-Control-Allow-Originは”*”ではなく必要なオリジンのみを設定しましょうね。

CORS有効化

詳しい設定方法はAmazon API Gatewayデベロッパーガイドを御覧くださいね〜。

因みに、私は今回AWS SAMを使用していたため、template.yaml内で簡単に設定ができました。


Resources:
  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Cors:
        AllowMethods: "'POST, OPTIONS,'"
        AllowHeaders: "'Origin, Authorization, Accept, Content-Type'"
        AllowOrigin: "'設定するオリジン'"

なんて便利なんだ…。
これで無事にネットワーク上でAPI通信を行うことができるようになりました。

今回の問題はCORSについてきちんと学べる良い機会となりました。
まだ全て理解はできていないようにも思いますが、基本のキの字くらいは理解できたかな。