非公式なのでよほど困った時に参考にする程度にしてください。
個人の備忘録です。
usersテーブルは標準のままでuser_infosテーブルにenable(bool)カラムを設けるものとします。
user_infosテーブルはusersと一対一でリレーションしているものとします。
まず、User
モデルに userInfo()
リレーションを定義します。
// app/Models/User.php
public function userInfo()
{
return $this->hasOne(UserInfo::class);
}
次に排他を実装します。
ミドルウェアを作成します。
app/Http/Middleware フォルダは無くなったとかの情報があったりなかったりしますが、コマンド実行時に作成されるのでカスタムミドルウェアの保存場所としては正式なのかもしれません。
php artisan make:middleware CheckUserStatus
カスタムミドルウェアを登録します。
<?php
// bootstrap/app.php
use App\Http\Middleware\CheckUserStatus;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
use Illuminate\Foundation\Http\Middleware\TrimStrings;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
// 無効ユーザーの排他を実装
$middleware->append(CheckUserStatus::class);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
カスタムミドルウェアの中身
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\Auth;
class CheckUserStatus
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$user = $request->user();
if ($user && (!$user->userInfo || !$user->userInfo->enable)) {
Auth::logout();
// エラーメッセージとリダイレクト
return redirect('/login')->withErrors(['email' => 'このアカウントは無効です。']);
}
return $next($request);
}
}
web.phpにカスタムミドルウェアを実装
Route::middleware(['auth', CheckUserStatus::class])->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
// ユーザー削除は管理者のみ実施できるものとします。
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
Laravel10までと違って、連想配列でミドルウェアを登録しないので「CheckUserStatus::class」で割り当てます。
名前空間も必要なので、従来の文字列で割り当てても動きません。
その前の「’auth’」は文字列で割り当たっているので暗黙的に解決する場所があるのかもしれません。
実際にこれで動作しました。
初期設定だけ済めば、web.phpに割り当てるだけなのでシンプルなのかなと思います。
これだと、ユーザーが作業中に管理者がuser_infos.enableをfalseにすると次のアクションで排他されます。
ログイン部とセッション管理部で排他する必要はありません。
パスワードリセットやメール認証部にも必要かなと考えましたが、そちらは排他せず処理が成功したとしても認証済アクションに入ると排他されるので不要と考えました。