Laravelのセッション管理(認証機能)についてまとめて

# はじめに
Laravelのセッション管理(認証機能)についてまとめてみました。

# まず、用語
## Cookie(クッキー)
* テキスト情報
* HTTPレスポンス
  - Set-CookieヘッダーフィールドにCookieフィールドに「Set-Cookie: クッキー名=値; 属性名=属性値;属性名=属性値 …」形式で挿入される

* HTTPリクエスト
  - Cookieフィールドに「Cookie: クッキー名=値; 属性名=属性値;属性名=属性値 …」形式で挿入される

クッキーとは**HTTPレスポンス、HTTPリクエストに設定されるクッキー名=クッキー値の名前と値の組のテキスト情報のこと**

http://e-words.jp/w/Cookie.html

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Set-Cookie

* 値の後に属性が続く場合は、「;」（半角のセミコロン）で区切られて並ぶ。
* 属性値は必須ではない
* クッキーの送信する適用範囲をpath属性、domain属性で指定する
  - https://www.atmarkit.co.jp/ait/articles/1704/20/news024_2.html
* 複数指定する場合。例レスポンス。複数のSet-Cookiフィールドにクッキーを指定する。リクエストも同様。 
  - Set-Cookie: クッキー名1=値;
  - Set-Cookie: クッキー名2=値;



## Cookie(クッキー)保存場所
* ローカルの端末内にあるテキストファイルにクッキーが保存される
* いろんなクッキーの説明をみると、この領域もクッキーと呼んだり、呼ばなかったりしているように見える。

## クッキーをどう使うのか
HTTP通信は状態を維持できない(初回のHTTP通信と、次のHTTP通信が同じユーザであることを判別できない)ので**クッキーを使うことで(クッキーに通信を識別する情報を保持して)状態を維持できるようになる(ユーザーを判別できるようになる)。**

## セッションIDとセッション管理
* セッションIDとは、Webアプリケーションなどで、通信中の利用者を識別して行動を捕捉し、利用者ごとに一貫したサービスを提供するために付与される固有の識別情報。そのような仕組みをセッション管理という。

* 意味合い的にはユーザーを識別するためのラベル(受付番号)のようなもので、ランダムな文字列(例：jZ6VkVkVUIyNHJPNSIsIm...)
* セッションIDはユーザーIDを暗号化したものではない


http://e-words.jp/w/%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3ID.html

**クッキーにセッションIDをのせて、クライアント、サーバー間で通信することでユーザーを識別できるようになる**

## クッキーを利用したセッション管理の流れ
* クライアント: ログインします(HTTPリクエスト)
* サーバー　　: OK－。HTTPレスポンスにset-Cookie: key=value　(**valueにセッションIDが入る**)を設定してクライアントに送信
  - set-Cookieとはクッキー(クッキー名=クッキー値)を保存してください&次回以降はHTTPリクエストにクッキー(クッキー名=クッキー値)を付加して情報も送ってくださいという命令
* クライアント: 次回以降はクッキー名=クッキー値がHTTPヘッダフィールドに記載されたHTTPリクエストをサーバに送付する


# Lavavelのセッション
## Laravelバージョン
Laravel Framework 5.8.35

## Laravelでのセッション管理
config/auth.phpでLaravelでセッション管理する場合の操作方法を決めます。操作方法には`file`や`cookie`、`database`など幾つかの方式をサポート。デフォルトだとfile方式でセッションを管理するようになっています。

```config/session.php

  7     /*
  8     |--------------------------------------------------------------------------
  9     | Default Session Driver
 10     |--------------------------------------------------------------------------
 11     |
 12     | This option controls the default session "driver" that will be used on
 13     | requests. By default, we will use the lightweight native driver but
 14     | you may specify any of the other wonderful drivers provided here.
 15     |
 16     | Supported: "file", "cookie", "database", "apc",
 17     |            "memcached", "redis", "dynamodb", "array"
 18     |
 19     */
 20
 21     'driver' => env('SESSION_DRIVER', 'file'),
```


# Laravelのセッション管理
Laravelでは幾つかの方法でセッションを管理することが分かりました。今度はセッション管理がCookieの場合とfileの場合にどうやってHTTPアクセスからユーザーを識別しているのか調べてみました。

## セッション管理がfileの場合
* ユーザーがサーバにログインした際にサーバ側では`storage/framework/sessions/セッションID`の`ファイルを作成`して中身にはusersテーブルの主キー=users.idを記入
* サーバからのHTTPレスポンスにはSet-Cookieヘッダに暗号化されたセッションID(クッキー)が記述されていて、クライアントは端末に暗号化された`セッションID`(クッキー)を保存
* 以降、ユーザの**HTTPリクエスト毎**にリクエストのCookieヘッダからクッキー(下記画像のvalue)の`セッションID`をとりだして同じ`storage/framework/sessions/セッションID`ファイルを探し出し、中身のusersテーブルの主キーを見て、どのユーザーからのアクセスなのかを理解している。

下記画像が実際のクッキーの値valueに暗号化されたセッションIDが入っている
![laravel-session.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273424/8eb44a2a-5fbf-8ee0-db52-d0b08d19f480.png)


ユーザの識別情報があるstorage/framework/sessions/セッションIDの中身

```storage/framework/sessions/セッションID
.
.
{s"login_xxx_暗号化";i:ユーザーID(usersテーブルの主キー);} ← これでユーザーを特定する
```

暗号化されたセッションIDを復号

```bash
Crypt::decryptString("eyJpdiI6InFQ.........");
=> "M9fH83wgHK6Nze..."
```

↑のセッションIDの値がファイルとして作成されている

```bash
ll storage/framework/sessions/M9fH83wgHK6Nze...
```

## セッション管理がCookieの場合

nameが暗号化なしのセッションIDになっていて、valueに上記fileセッション管理の時の**storage/framework/sessions/セッションIDファイルの中身がそのまま書かれている**

![laravel-cookie.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273424/7987d061-6877-e30b-dec4-73a7af2aec83.png)


valueの中身を確認してみた。暗号化されているのでdecryptStringで復号すると上記fileセッション管理の時のstorage/framework/sessions/セッションIDファイルの中身がそのまま書かれていた。

```bash
>>> Crypt::decryptString("eyJpdiI6IlNiUWFLN1l4M3JKWmtoSlVxQWV0eEE9PSIsInZhbHVlIjoiUU9NdjE4V2VsYUhFMGJmc1FwUDZHWXpjMkYzNGphRHg3cTc2M1l1QTArcTJZVXdFczlvUnYzaXdPMDZ4MFlPYmh2NDlcL3lY・・・");
=> "{"data":"a:5:{s:6:\"_flash\";a:2:・・0:\"xxxxxxxx\";s:3:\"url\";xxxx:{}s:9:\"_previous\";a:
1:{s:3:\"url\"xxxx:\"http:\/\/xxxxxxxx";}s:5s"login_xxx_暗号化";i:ユーザーID(usersテーブルの主キー);","expires":1572584018}"
```

ユーザーを識別する仕組みはfileの時と同様で、クッキーを取り出して複合化して、usersテーブルの主キーをみてどのユーザからのアクセスか判定している。

**クッキーの中に情報そのものをか格納するのか、セッションIDだけを格納するのかが大きな違い**