やりたいこと
- Laravelの認証処理
php artisan make:auth
を使用 - 作成される
User
テーブルに無効フラグを追加し、無効なユーザーではログインさせない
やったこと
とりあえずググってみた結果、以下の内容がよく出てきた。
- 認証対象の項目を指定しているのは
AuthenticatesUsers
トレイトのcredentials
メソッド -
LoginController
でcredentials
メソッドをオーバーライドして条件追加
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の実装調査 ~ログイン編・リメンバーログインもあるよ~
この記事によれば SessionGuard
の userFromRecaller
で処理されてるらしい。
更に追いかけるとUserProvider
の retrieveByToken
の中が肝っぽい。
config
配下を確認すると
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
],
driver
が eloquent
なので実装は Illuminate\Auth\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;
}
ID
と rememberToken
しか見てなかった。。。
クッキーさえ残っていればいつまでもログイン状態になってしまうので困る。
じゃあどうするか
UserProvider
自分でカスタマイズしたほうがよさそう。
あ、LoginController
は元に戻しました。
カスタムUserProvider作成
<?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();
}
}
認証サービスの登録
<?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 に追加
'providers' => [
'users' => [
// 'driver' => 'eloquent',
'driver' => 'custom_eloquent', // カスタマイズ
'model' => App\User::class,
],
],
結果
-
「ログイン状態を維持」でもセッションが切れたら再ログインが必要になった。ヤッタネ
-
セッションも強制的に切りたいなら
SessionGuard.php
のuser()
メソッドのオーバーライドになるかな…? -
LoginController
のcredentials
オーバーライドはちょっと使い道が思いつかない。
ログイン時はチェックするけど、リメンバーログインではチェックしない条件とかあるんなら使えそう。
または「ログイン状態を維持」を使用しないとか。
どちらにせよUserProvider
の継承で対応できるから敢えて選ぶメリットはない気がする。