問題
LaravelでAPIを作ってて、Sanctumを利用してユーザー認証を実装し、開発環境では動作しました。そこで検証環境に持って行ったところ「ログインは成功するが、そのあと認証が必要なAPIにアクセスすると『401 Unauthorized』エラーで弾かれる」という現象が発生しました。
(私の場合の)原因
- そもそも開発環境用の.envだけ設定してて、検証環境用の.envにSanctum周りの設定するの忘れてた
- 1を受けて設定したものの、.envのSANCTUM_STATEFUL_DOMAINSの記載が間違っていた
原因1に関しては「実装できた~✌」と完全に気が抜けてましたね……スーパーアホでした😅
原因2に関してはDocker上で開発してて、雑にlocalhostで設定していても動いてしまっていたので、仕様をちゃんと理解できてなかったのが原因です。
調査
.envの反映し忘れの線はすぐに当たりましたが駄目。ブラウザの開発者ツールで401しか出ず、Cookie周りも正常動作してるように見えました。「(デプロイ自動化してないので)検証環境のライブラリ自体にロガー仕込むの面倒くさい」と、ググり倒したり設定弄り回したりあがいてみましたが、これも駄目でした。
ただ調べる過程でこの記事を見かけて、どのクラスに仕込めばいいのか当たりがつきました。大変助かりました🙏
// \vendor\laravel\sanctum\src\Http\Middleware\EnsureFrontendRequestsAreStateful.php
public static function fromFrontend($request)
{
$domain = $request->headers->get('referer') ?: $request->headers->get('origin');
if (is_null($domain)) {
return false;
}
$domain = Str::replaceFirst('https://', '', $domain);
$domain = Str::replaceFirst('http://', '', $domain);
$domain = Str::endsWith($domain, '/') ? $domain : "{$domain}/";
$stateful = array_filter(config('sanctum.stateful', []));
return Str::is(Collection::make($stateful)->map(function ($uri) {
return trim($uri) . '/*';
})->all(), $domain);
}
メソッド名から察しがつくかと思いますが、Webブラウザからのアクセス(Session使える)か、CLIアクセス(Session使えない)かの判定ですね。
「refererあるいはorigin、SANCUM_DOMAIN_ORIGINSを加工した上で比較してるんだな」というのが分かって、Str::isも調べてようやく、SANCTUM_STATEFUL_DOMAINSに「www.」のないドメインを登録してて、$domainとマッチしてないことに気づきました。.envの他の項目とごっちゃになったか、省略可能だろうと当てずっぽうに設定した線が濃厚です😅
「www.」を含めたドメイン名を設定することで無事動きました。
感想
ググった限り、このトラブルはそこそこある上に、原因となる要素が多いんで、StackOverFlow等でも「更新後の.envちゃんと適応してる?」とか「sessionタイプをcookieにしろ(注:デフォルトのfile設定で動きます。誤解してる人の書き込みがあるので注意)」等、場当たり的なアドバイスが多いです。チェックリストの必要性を感じましたね……誰か作ってください。(怠慢)
またsession管理がファイルの場合だと書き込み権限絡みで失敗するパターンもあるみたいなんで、この問題にハマっている人はチェックしてみてください。
それと身も蓋もないですが「(検証環境とはいえ)APP_DEBUG=trueにしたらもっと早く分かったんじゃね」と今書いてて思いましたw デプロイが手作業なこと、マルウェア問題の記事を読んだ直後で、検証環境でAPP_DEBUG=trueするのに抵抗があったので、思いついても実行出来たかどうか微妙ですが……。
🙏Laravel公式ドキュメント翻訳者への支援のお願い
Laravelの公式ドキュメントの日本語版であるReaDouble.comを運営されている川瀬裕久氏が、広告収入の低下と持病の悪化のため、翻訳プロジェクトを継続することが困難になり、GitHub sponsorsを募集しています。 日本のLaravelユーザーでここを見たことない人はいないと思うので、もし恩義を感じているならば是非支援のほどお願いします。私も支援させていただいております