7
7

More than 3 years have passed since last update.

Laravelのログイン認証条件を追加しつつログイン維持条件も追加する

Last updated at Posted at 2019-10-29

やりたいこと

  • Laravelの認証処理 php artisan make:auth を使用
  • 作成される User テーブルに無効フラグを追加し、無効なユーザーではログインさせない

やったこと

とりあえずググってみた結果、以下の内容がよく出てきた。

  • 認証対象の項目を指定しているのは AuthenticatesUsers トレイトの credentialsメソッド
  • LoginControllercredentials メソッドをオーバーライドして条件追加
LoginController.php

use Illuminate\Http\Request;

class LoginController extends Controller
{
    protected function credentials(Request $request)
    {
        $arr = $request->only($this->username(), 'password');
        $arr['disable'] = 0;    // 無効フラグOFFの条件を追加

        return $arr;
    }
}

できた~と思ったら…

問題点

ログイン状態を維持」でログインした場合、
その後対象ユーザーの無効フラグを立ててもログイン状態が維持される。
(一度ログアウトすると再ログインは不可になる)

調査結果

Laravelの実装調査 ~ログイン編・リメンバーログインもあるよ~

この記事によれば SessionGuarduserFromRecaller で処理されてるらしい。
更に追いかけるとUserProviderretrieveByToken の中が肝っぽい。
config 配下を確認すると

auth.php

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
    ],

drivereloquent なので実装は Illuminate\Auth\EloquentUserProvider.php

EloquentUserProvider.php

<?php

// ・・・・

class EloquentUserProvider implements UserProvider
{
    public function retrieveByToken($identifier, $token)
    {
        $model = $this->createModel();

        // UserモデルからIDで引っ張る
        $model = $model->where($model->getAuthIdentifierName(), $identifier)->first();

        if (! $model) {
            return;
        }

        // rememberTokenが一致すればOK
        $rememberToken = $model->getRememberToken();

        return $rememberToken && hash_equals($rememberToken, $token) ? $model : null;
    }

IDrememberToken しか見てなかった。。。
クッキーさえ残っていればいつまでもログイン状態になってしまうので困る。

じゃあどうするか

UserProvider 自分でカスタマイズしたほうがよさそう。
あ、LoginControllerは元に戻しました。

カスタムUserProvider作成

CustomEloquentUserProvider.php

<?php

namespace App\Auth;

use Illuminate\Support\Str;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Contracts\Auth\Authenticatable;

class CustomEloquentUserProvider extends EloquentUserProvider
{
    // rememberToken認証のやつ
    public function retrieveByToken($identifier, $token)
    {
        $model = $this->createModel();

        $model = $model->where($model->getAuthIdentifierName(), $identifier)
                        ->where('disable', 0)   // disable指定を追加
                        ->first();

        if (! $model) {
            return;
        }

        $rememberToken = $model->getRememberToken();

        return $rememberToken && hash_equals($rememberToken, $token) ? $model : null;
    }


    // ログイン時のやつ
    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials) ||
           (count($credentials) === 1 &&
            array_key_exists('password', $credentials))) {
            return;
        }

        $query = $this->createModel()->newQuery();

        foreach ($credentials as $key => $value) {
            if (! Str::contains($key, 'password')) {
                $query->where($key, $value);
            }
        }

        // disable指定を追加
        return $query->where('disable', 0)->first();
    }
}

認証サービスの登録

AuthServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Application;

use App\Auth\CustomEloquentUserProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * アプリケーションのためにマップ付けるポリシー
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * 認証/認可サービスの登録
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        // 追加
        Auth::provider('custom_eloquent', function (Application $app, array $config) {
            return new CustomEloquentUserProvider($app['hash'], $config['model']);
        });
    }
}

config に追加

auth.php

    'providers' => [
        'users' => [
            // 'driver' => 'eloquent',
            'driver' => 'custom_eloquent',  // カスタマイズ
            'model' => App\User::class,
        ],
    ],

結果

  • 「ログイン状態を維持」でもセッションが切れたら再ログインが必要になった。ヤッタネ

  • セッションも強制的に切りたいなら SessionGuard.phpuser() メソッドのオーバーライドになるかな…?

  • LoginControllercredentials オーバーライドはちょっと使い道が思いつかない。
    ログイン時はチェックするけど、リメンバーログインではチェックしない条件とかあるんなら使えそう。
    または「ログイン状態を維持」を使用しないとか。
    どちらにせよUserProviderの継承で対応できるから敢えて選ぶメリットはない気がする。

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