🕋

Laravel Sanctumサーバとローカル開発環境でAjax通信(CORS)したい

2022/10/04に公開

やりたいこと

Laravel Sanctumで構築したクラウドサーバと、ローカル開発しているwebページを通信したい。
サーバは、HTTPS × Basic認証で、ローカルはHTTP。

想定している環境

サーバ(PHP)環境

  • Apache
  • Laravel Sanctum
  • Basic認証あり
  • EC2 -> Cloud Front
  • HTTPS環境

ローカル環境

  • HTTP環境
  • axios使用

手順

通信するために2種類の設定が必要

  1. CORS(別ドメイン) + Basic認証 + Ajax(axios)の通信
  2. Laravel SanctumでCORS通信を許可

CORS(別ドメイン) + Basic認証 + Ajax(axios)の通信設定

Basic認証をつけたサーバでHTMLを開いた場合は、Basic認証のダイアログが表示されるが、
別ドメイン(CORS)からアクセスすると、CORS × Basic認証の部分ではまることがあるようだ。

詳しい解説は↓にあるように2つの許可が同時にとれない問題が発生する
https://qiita.com/yana1316/items/34ee351adb6091ea7fc1

解決方法も記事に書かれているので、そのように変更する。

# アクセスを許可するURLを指定
Header set Access-Control-Allow-Origin "https://example.hoge.com"

# 許可するリクエストヘッダのメソッドを指定
Header set Access-Control-Allow-Methods "POST, GET, OPTIONS"

# 許可するリクエストヘッダの種類を指定
Header set Access-Control-Allow-Headers "Content-Type, origin, authorization"

# プリフライトレスポンスをキャッシュする時間を指定
Header set Access-Control-Max-Age "600"

# OPTIONSに対する反応
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

<LimitExcept OPTIONS>
  AuthType Basic
  AuthUserFile /hoge/.htpasswd
  AuthName "ID and password"
  Require valid-user
</LimitExcept>

今回の環境では、CORSの許可はCDN(CloudFront)で出せるので、Basic認証でOPTIONを除外のみを行った。

<LimitExcept OPTIONS>
  AuthType Basic
  AuthUserFile /hoge/.htpasswd
  AuthName "ID and password"
  Require valid-user
</LimitExcept>

CloudFrontで、CORS設定はこちらを参考にした
https://aws.amazon.com/jp/premiumsupport/knowledge-center/no-access-control-allow-origin-error/

Laravel SanctumでCORS通信を許可

基本的にドキュメントに従って進める。
https://readouble.com/laravel/9.x/ja/sanctum.html?header=%25E3%2582%25A4%25E3%2583%25B3%25E3%2582%25B9%25E3%2583%2588%25E3%2583%25BC%25E3%2583%25AB#cors-and-cookies

まず、credentials を有効化

Laravelのconfig/cors.php
// 中略
'supports_credentials' => true

次に、 .env を下の例のように設定を追加する

.env
SANCTUM_STATEFUL_DOMAINS=http://localhost:3000,http://127.0.0.1:3000,http://localhost#開発環境を指定する。SANCTUM認証除外対象
SESSION_DOMAIN=.hoge.com#サーバのドメイン。"."から書くとサブドメインも対象にする
SESSION_SECURE_COOKIE=false#開発がHTTP環境なので指定する

()

SANCTUM_STATEFUL_DOMAINS 項目はドキュメントではドメインのみ記載している。
しかし、http から書かないとサーバが https ローカルが http だとうまくいかないのに注意。

サーバ側の設定はこれで終わりです。

Webで通信を設定

axiosライブラリで、Ajaxを設定する。
web側で、CORS通信のために withCredentialsを有効化する。
また、sanctumのAPIにアクセスする前に /sanctum/csrf-cookie でcookieを取得する必要があります。
コードの例は下のようになると思います。

JS通信例
axios.defaults.withCredentials = true// CORSするためにCredentialsを有効化
axios.defaults.baseURL = 'https://hoge.com'// サーバのドメインを設定

/** SanctumのAPIにアクセスする前にこちらのAPIを踏む必要がある */
const apiStartUp = async ()=>{ return axios.get('/sanctum/csrf-cookie', {
    auth: {// 送信するbasic認証
        username:'hoge',
        password:'fuga'
    }})
};

apiStartUp().then(()=>{
	//通信成功を待って、他の通信を行う
	await axios.get('/api/hoge')// <-本命の通信
});

終わり

どの問題もそれなりに情報があるが、微妙に領域が重なるところで問題が起こり調べるのに時間がかかった。
まとめた、ドキュメントをここに記載しておきます。
誰かの役に立つと幸いです。

Discussion