9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Laravel】 Sanctum で任意のタイミングでCookieの発行を許可する 【SPA】

Posted at

Sanctum の仕組み

@ucan-lab さんの記事で結構詳しく書かれているのでまずはこちらを参考のこと

Cookie 発行の条件

Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful が特定条件でCookieを暗号化したり発行したりしてくれます。その特定条件とは

  • refererヘッダー が存在し、その値が sanctum.php で指定したドメインに含まれる。
  • ↑がなければ originヘッダーが存在し、その値が sanctum.php で指定したドメインに含まれる。

です。

その判定は上記ファイル内の fromFrontend() メソッドで行われています。

sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php
    public function handle($request, $next)
    {
        $this->configureSecureCookieSessions();

        return (new Pipeline(app()))->send($request)->through(static::fromFrontend($request) ? [
            function ($request, $next) {
                $request->attributes->set('sanctum', true);

                return $next($request);
            },
            config('sanctum.middleware.encrypt_cookies', \Illuminate\Cookie\Middleware\EncryptCookies::class),
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            config('sanctum.middleware.verify_csrf_token', \Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class),
        ] : [])->then(function ($request) use ($next) {
            return $next($request);
        });
    }

        // Cookieを付与するか判定するメソッドはこれ
    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);
    }

Referer ヘッダ、 Origin ヘッダが付与されない

特定のブラウザで、 OAuth のフロー内でリダイレクトされてAPIにリクエストが飛んでくる場合などに、 referer ヘッダが付与されない状態でリクエストが飛んでくる場合があるそうです。

そうした場合、通常であれば OAuth の認証をもとに Cookie を発行したいという要望が答えられませんが、上記のファイルを継承させて、オーバーライドすれば対応可能です。

やること

  • sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php を継承したファイルを作成し、fromFrontend()をオーバーライドする
  • 新しく設定した条件に脆弱性がないか十分に検討する。
  • Kernel.php を api の middleware に登録する。

その他

Auth::guard('sanctum') の実態

最後の行だけ読めばOKです。

  • 実態としては Illuminate\Auth\RequestGuard
  • ミドルウェアを挟んだ場合に配下のリクエストで必ず呼ばれる check() メソッドがあり、その中で RequestGuarduser() メソッドが呼ばれるが、user() メソッド内で sanctum の Guard.php__invoke() され、その際に Auth::guard('web')->user() が呼び出され return される。
  • なので、 Auth::guard('sanctum')->user() をすると Auth::guard('web')->user() の結果が返ってくる。
9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?