1
2

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 マルチログインでセッションをDB管理する方法

Posted at

投稿理由

マルチログインでセッションをDB管理する場合、最低でもテーブルにカラムを管理者側とユーザーで用意する必要があります。
ですが、実装例として参考になる記事が少なく苦労したので、後発者の参考になればと思い投稿しました。
DatabaseSessionHandler.phpを普通にオーバーライドしても読み込んでくれなかったのでここがポイントになります。
Laravel経験が浅いため、誤っている箇所があるかもしれません。

環境

Laravel9系
MYSQL
Docker
VSCode(Dev Containers使用)

前提

マルチログイン実装済みのものとします。
Laravel マルチログインで調べればいくらでも出てくるのでここでは割愛します。

全体像

最終的な修正ファイルのディレクトリ
修正対象以外はすべて省略しています。

src/
   ├ app/
   │    ├ Providers/
   │    │          └ SessionServiceProvider.php 新規作成
   │    └ Session/
   │             └ DatabaseSessionHandler.php 新規作成
   │
   ├ config/
   │       ├ app.php 既存を修正
   │       └ session.php  既存を修正
   │
   └ database/migrations/
                        └ yyyy_mm_dd_△_create_sessions_table.php  新規作成

修正内容

①config/session.php

config/session.php
'driver' => env('SESSION_DRIVER', 'file'),
// ↓下へ修正
'driver' => 'database',

②Session管理用テーブルの作成

以下のコマンドを実行

php artisan session:table

③ ②で作成したマイグレーションファイルを修正

yyyy_mm_dd_△_create_sessions_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class () extends Migration {
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('sessions', function (Blueprint $table) {
            $table->string('id')->primary();
            $table->foreignId('user_id')->nullable()->index();
            $table->foreignId('admin_user_id')->nullable()->index();
            $table->string('ip_address', 45)->nullable();
            $table->text('user_agent')->nullable();
            $table->longText('payload');
            $table->integer('last_activity')->index();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('sessions');
    }
};

④テーブルの作成

php artisan migrate

⑤app/Providers/SessionServiceProvider.php

作成して以下の内容にする。

app/Providers/SessionServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;
use App\Session\DatabaseSessionHandler;

class SessionServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Session::extend('database', function ($app) {
            $connection_name = $this->app->config->get('session.connection');
            $connection      = $app->app->db->connection($connection_name);
            $table           = $this->app->config->get('session.table');
            $lifetime        = $this->app->config->get('session.lifetime');

            return new DatabaseSessionHandler($connection, $table, $lifetime, $this->app);
        });
    }
}

⑥app/Session/DatabaseSessionHandler.php

作成して以下の内容にする。
一部書き換える必要がありますが、マルチログインの場合URLが系統ごとに異なってる場合が多いと思うのでそこからとればいいと思います。
Authから取ろうとしましたが、うまくとれずこの形になってます。もっとよい形があると思います。

app/Session/DatabaseSessionHandler.php
<?php

namespace App\Session;

use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Container\Container;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Support\Facades\Route;

class DatabaseSessionHandler extends \Illuminate\Session\DatabaseSessionHandler
{
    /**
     * Add the user information to the session payload.
     *
     * @param  array  $payload
     * @return $this
     */
    protected function addUserInformation(&$payload)
    {
        if ($this->container->bound(Guard::class)) {
        // Authから取得できなかったのでURLから画面系統を取得
        $guard = isset(explode("\\", Route::currentRouteAction())[キー]) ? explode("\\", Route::currentRouteAction())[キー] : '';
            # ここに条件を入れる。
            if ($guard === '画面系統') {
                $payload['user_id'] = $this->userId();
            # ここに条件を入れる。
            } elseif ($guard === '画面系統') {
                $payload['admin_user_id'] = $this->userId();
            }
        }

        return $this;
    }
}

以上でDBで管理できます。

補足 テーブルを分けず、カラムを分けるだけの実装理由について

テーブルを分けると認証が切れるためです。
※管理者側ログイン→ユーザーログイン とすると管理者側がセッション切れしてしまいました。逆でも同様の現象になります。
別テーブルでも良いようにさらにオーバーライドして修正してもよいですが、そこまで困らないので()

終わりに

後発者の方の参考になれば幸いです。

1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?