【laravel】プロジェクト間のsession共有について
laravelを使用したプロジェクトでapiとview部分で分離された二つのプロジェクトを作成した際に、認証情報を共有するためにsessionを共有したプロジェクトを作成した際のメモです。
初期はjwtを使用していましたが、理解度の問題でsessionに変更することになり、試行削除した内容です。
結論としては
- APP_KEYを同じにする
- 保存場所を同じにする( とりあえずdatabase )
- config/auth.phpの「guards」のkey名称を合わせる
APP_KEYを同じにする
.envのAPP_KEYを同じ値にします。
laravelは初期設定で「php artisan key:generate」コマンドでAPP_KEYを作成しますが、どちらかの設定に合わせる必要があります。
保存場所を同じにする( とりあえずdatabase )
sessionの保存方式で異なりますが、fileの場合は「storage/framework/sessions/」に保存されると思います。このpathは「config/session.php」のfilesが設定になっています。同じサーバーにある場合はどちらかのプロジェクトに合わせれば大丈夫です。
datbaseの場合はDBにテーブルを作成して参照する形になります。テーブルはartisanコマンドでmigrationファイルが作成することが可能です。
php artisan session:table
.envの設定で「SESSION_DRIVER」を「databse」に変更して完了です。
「guards」のkey名称を合わせる
「laravel session 共有」で調べると上記2つのことが書かれている記事があり、参考に設定しましたが自分の環境ではなぜか認証されず401エラーになりました。
laravelのsession作成のコードを追うとguardsのキー名を利用している部分があり、プロジェクトでkeyが違ったため認証されていなかったみたいです。
guardsのキー名を同じにすることで認証することを確認できました。
管理と利用者画面でcookieを分ける
またプロジェクトで管理、利用者、apiと分けるケースも出てくると思います。同じにした状態で利用すると、利用者での認証情報が管理画面で使用できてしまう懸念があるためcookie分けることにしました。
apiプロジェクトの.envにSESSION_COOKIE_USERを追加して、二つ作成できるようにします。
SESSION_COOKIE=shared_cookie SESSION_COOKIE_USER=shared_user_cookie
config/session.phpに設定を追加
'cookie' => env( 'SESSION_COOKIE', Str::slug(env('APP_NAME', 'laravel'), '_').'_session' ), 'cookie_user' => env( 'SESSION_COOKIE_USER', Str::slug(env('APP_NAME', 'laravel'), '_').'_session_user' ),
app/Providers/AppServiceProvider.phpのbootに関数追加。url次第で使用するcookieを切り替えます。
public function boot() { if (request()->is('api/v1/user*')) { config(['session.cookie' => config('session.cookie_user')]); } }
なぜJWTを辞めたのか
JWTはステートレスで認証可能なtoken方式の仕組みです。
ここ数年は自分のプロジェクトで使用して便利なことを実感していましたが、認証情報の更新周りで色々と試行錯誤が必要になり、いままで利用してきたsessionに戻すことにしました。
更新周りで勘違いしていた部分は、トークンの有効期限(JWT_TTL:デフォルト1時間)とリフレッシュ有効期限(JWT_REFRESH_TTL:デフォルト2週間)の設定について間違った認識をして使用していました。
リフレッシュ有効期限の期間内に更新をすれば新しいtokenとして再度2週間更新なtokenになるとおもっていましたが、一番最初に発行した時点での2週間以内なら更新可能。という意味でした。
パラメータとしては「iat」の数値が変わらないため期限が来たら更新できなくなりました。
“iat” (Issued At) (Optional) JWTが発行された日時を意味します。
仕様の理解度が足りていない状態で動くから大丈夫。と思って使っていましたが運用になると色々と問題が出てしまい反省しました。
一応、更新用のtokenを発行して再度新規のtokenを発行できるような仕組みも作成しましたがどうにもコードの事例がなかったので、セキュリティ的な面でみても不安になり、jwtのやめる判断をしました。
jwt自体はサーバーの認証情報の保存場所を意識せず開発することができたため便利なことは実感できましたが、周りに利用する開発者が少ないこともあり無難な方式が良いという結論になりました。
実は簡単な方法での解決法
apiとviewのプロジェクトを一緒にしてしまえば今回の対応をする必要はありません。
apiとviewを別プロジェクトで作成してかなり作り込んでしまったため共有する方法を採用しています。
またapiをプロジェクトとして分けた理由は管理画面と利用者画面で同じコードを使用することを想定していたためのプロジェクト構成になっています。
構成は最初に結構悩みますが、今後作成する場合は同じプロジェクトでapiとviewを作ると思います。
デメリットとしてapiが冗長なコードになったり、仕様変更を管理画面と利用者画面のどちらにも反映しないとダメな構成になりますが、あまりどちらにも影響のある変更は現状少ないため当分はこの方針でいいかと思ってます。
ただapiを分ける構成自体は正直良いと思っているため認証部分さえ解決できればapiをプロジェクトとして分けるのは良いと思ってます。