セッションとは
http通信はブラウザ->サーバーへのステートレスな通信のため、サーバー側では誰がブラウザから通信を投げているかが不明(リクエスト元を認識できない)なのですが、
同一ユーザーからの複数のリクエスト(セッション)を管理するために活用されているのがCookieです。(これにより、例えばECサイトのショッピングカートに入れた商品を一定時間保持することが可能です)
ブラウザからリクエストを送ると、サーバー側でCookieが含まれたレスポンスが作成され、レスポンスが返されることによってブラウザに保存されます。(サーバーサイドクッキー ※ブラウザ側で作ることも可能です)
例えば、認証情報だと、ログイン完了後にサーバー側でクッキーを作成して、セッションidを保存し、ブラウザに返します。(Cookieのkey&valueのうち、valueにセッションidを保存する)
これにより、次回以降はクッキーに保存されているセッションidをサーバーに投げることで、セッションidからサーバー側で認証を判定することで簡単にログイン可能になります。
Laravelでのセッションの仕組み
laravelにはセッションを利用して認証を行う仕組みが用意されているので、そちらを元にご紹介したいと思います。公式ドキュメントにも記載がありますので、詳細は下記リンクから参照ください。
https://readouble.com/laravel/8.x/ja/sanctum.html
ブラウザ
まず、ブラウザを起動して、”/”にアクセスします。(この段階では未認証)次に、ChromeデベロッパーツールのApplicationタブからCookieを確認します。
デフォルトではcookieの名前がlaravel_sessionとなっていますが、session.phpファイルのcookieパラメータで変更可能です。.envファイルのAPP_NAMEの名前を変更してもcookieの名前は変わります。
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
cookieが作成されるタイミング
cookieはLaravelから戻されるResponseヘッダーの中の”Set-Cookie”の値をブラウザが受け取ることで作成されます。
LaravelのSession IDを保存するCookie(デフォルト名はlaravel_session)の作成処理はmiddlewareのStartSessionの中で行われています。作成の詳細を確認したい場合は\Illuminate\Session\Middleware\StartSessionのaddCookieToResponseメソッドの中をみてください。
protected function addCookieToResponse(Response $response, Session $session)
{
if ($this->sessionIsPersistent($config = $this->manager->getSessionConfig())) {
$response->headers->setCookie(new Cookie(
$session->getName(), $session->getId(), $this->getCookieExpirationDate(),
$config['path'], $config['domain'], $config['secure'] ?? false,
$config['http_only'] ?? true, false, $config['same_site'] ?? null
));
}
}
cookieの暗号化
Laravelではcookieを出力する場合に、ミドルウェア(\App\Http\Middleware\EncryptCookies)によって標準で暗号化されています。
【補足】CookieのXSRF_TOKENについて
ブラウザ側に保存されているCookieの中には、Session IDを保存したLaravel_sessionとXSRF_TOKENの2つがあることがわかります。XSRF_TOKENはCSRF(クロスサイトリクエストフォージェリ)対策に使用するためのTOKENデータです。
通常のPOSTアクセスではフォームに埋め込んだCSRFトークンを利用して、その値をチェックすることでフォームを送ってきたページが正しいページなのかを判断しますが、XSRF_TOKENは入力フォームではなくaxiosを利用してpostリクエストを送信する際に利用します。
XSRT_TOKENとCSRF_TOKENがありますが、両者の違いは暗号化を行っているかどうかです。XSRF_TOKENは暗号化されているためLaravel側ではmiddlewareのVerifyCsrfTokenで復号化を行っています。
そのため、VerifiCsrfTokenのmiddlewareをコメントアウトするとCookieにはXSRF_TOKENは保存されなくなります。それはVerifyCsrfTokenの中のaddCookieToResponseメソッドでヘッダーの”Set-Cookie”にXSRF-TOKENが設定されてブラウザに戻される処理が行われているためです。
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Laravel\Jetstream\Http\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
↓
protected function addCookieToResponse($request, $response)
{
$config = config('session');
if ($response instanceof Responsable) {
$response = $response->toResponse($request);
}
$response->headers->setCookie(
new Cookie(
'XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']),
$config['path'], $config['domain'], $config['secure'], false, false, $config['same_site'] ?? null
)
);
return $response;
}
データベース
サーバ側でSession情報を保存するsessionsテーブルにはどのような情報が保存されているのかも確認してみましょう。
テーブルにはマイグレーションファイルで設定されているid, user_id, ip_address, user_agent, payload,last_actitity列が確認できます。user_id以外はすべて埋まっていることが確認できます。
ip_addressにはアクセスしたIPアドレス、user_agentにはアクセスしたブラウザの情報が入っています。
SessionとCookieで同じIDを保持すると説明しましたが、sessionsテーブルのidに対応する値を持つものはCookie側にはありません。その理由は先述の通り、Cookieが持つIDが暗号化されているためです。
ログイン処理に伴う値の変更
下記のように、ユーザがログインした瞬間にcookieのlaravel_sessionの値が更新され、sessionsテーブルを見るとCookieと同じIDを持っている行のuser_idに値が入ります。
■ログイン前
cookie
session
ログイン前なので、user_idはnull
■ログイン後
cookie
ログインすると、laravel_sessionの値が更新される
session
ログインしたuserのuser_idがセットされる
セッションの有効期限
Laravelでは、Cookie(セッション)のExpiration(有効期限)は現在の時刻ではなく現在の時刻の2時間後になっています。これはデフォルトで有効期限が2時間に設定されているためです。
Sessionに関する設定はすべてconfig/session.phpファイル内に記述されており、有効期限はlifetimeパラメータで設定を行うことができます。.envファイルのSESSION_LIFETIMEパラメータでデフォルトの有効期限を変更することが可能です。
'lifetime' => env('SESSION_LIFETIME', 120),
.env
SESSION_DRIVER=database
SESSION_LIFETIME=120
.envファイルの設定変更を反映させるためにはphp artisan config:clearを実行してください。それでも反映されない場合はphp artisan serveコマンドで開発サーバを起動しなおしてください。
まとめ
いかがでしたでしょうか。webを理解する上でセッション(クッキー)は切っても切り離せない概念です。Laravelでは簡単にsessionを利用できる仕組みが備わっており、本記事ではセッションを用いたSPA認証の仕組み(laravel sanctum)を元にセッションの仕組みについて解説していますので、ぜひ参考にしてみてください。