はじめに
Laravelのカスタムミドルウェアと、認証・CRUD・権限管理を統合したTODOアプリの設計について学習したので、自分用の復習問題としてまとめます。
今回は、特に重要な内容を10問に絞って復習します。
参考:
- Laravel公式ドキュメント - Authentication
- Laravel公式ドキュメント - Eloquent Relationships
- Laravel公式ドキュメント - Authorization
① カスタムミドルウェア
Q1. 次の IsAdmin ミドルウェアは、ユーザーの状態に応じてどう動く?
public function handle(Request $request, Closure $next): Response
{
if (! auth()->check()) {
return redirect('/login');
}
if (! auth()->user()->isAdmin()) {
abort(403);
}
return $next($request);
}
答えを見る
- 未ログイン:ログインページへリダイレクトする
- ログイン済みの一般ユーザー:403 Forbiddenを返す
- 管理者:
$next($request)で次の処理へ進む
Q2. IsAdmin に admin という別名を登録するにはどう書く?
答えを見る
bootstrap/app.php の withMiddleware() で登録する。
use App\Http\Middleware\IsAdmin;
use Illuminate\Foundation\Configuration\Middleware;
->withMiddleware(function (Middleware $middleware): void {
$middleware->alias([
'admin' => IsAdmin::class,
]);
})
Q3. 次のルート定義は何をする?
Route::middleware(['auth', 'admin'])->group(function () {
Route::get('/dashboard', function () {
return view('dashboard');
});
});
答えを見る
グループ内のルートに、ログイン確認と管理者権限の確認を順番に適用する。
IsAdmin 自体がログイン確認も行う実装なら admin だけでも動くが、auth と権限チェックを分離すると役割が分かりやすい。
Q4. ログイン後のリダイレクト先をロールで分けるだけで、アクセス制御は十分?
答えを見る
不十分。URLを直接入力すれば、リダイレクト先以外のページにもアクセスを試みられるため、各ルート側でもミドルウェアやPolicyによる認可が必要。
② TODOアプリのデータベース設計
Q5. 次の外部キー定義は何をする?
$table->foreignId('user_id')
->constrained()
->cascadeOnDelete();
答えを見る
tasks.user_id から users.id への外部キー制約を作成する。
ユーザーが物理削除されたときは、そのユーザーに属するタスクもDBによって連鎖削除される。
Q6. statusとpriorityにデフォルト値を設定するメリットは?
$table->enum('status', [
'pending',
'in_progress',
'completed',
])->default('pending');
$table->enum('priority', [
'low',
'medium',
'high',
])->default('medium');
答えを見る
値を指定しなくても、新しいタスクは「未着手」かつ「中優先度」という一貫した状態で登録される。
enum により、DBに保存できる値も指定した候補に制限できる。
Q7. 次のカラムに nullable() が付いている理由は?
$table->text('description')->nullable();
$table->date('due_date')->nullable();
$table->string('image')->nullable();
$table->timestamp('completed_at')->nullable();
答えを見る
説明、期限、画像は必須ではないため。completed_at は、タスクが未完了の間は完了日時が存在しないため null を許可する。
③ モデルとタスクの権限
Q8. User と Task の1対多リレーションはどう定義する?
答えを見る
User モデルでは hasMany() を使う。
public function tasks()
{
return $this->hasMany(Task::class);
}
Task モデルでは belongsTo() を使う。
public function user()
{
return $this->belongsTo(User::class);
}
Q9. 一般ユーザーのタスク一覧を、次のように取得するメリットは?
$tasks = auth()->user()
->tasks()
->latest()
->paginate(10);
答えを見る
現在のユーザーと関連するタスクだけがクエリの対象になる。
Task::paginate(10) で全ユーザーのタスクを取得してから画面で隠すより、情報漏えいを防ぎやすい。
Q10. 一般ユーザーは自分のタスクだけ、管理者は全タスクを削除できるようにするには、どのような認可が必要?
答えを見る
削除対象のタスクに対して、次のどちらかを確認する。
- ログイン中のユーザーがそのタスクの所有者である
- ログイン中のユーザーが管理者である
return $user->isAdmin()
|| $user->id === $task->user_id;
画面上のボタンを隠すだけではなく、Task Policyなどを使ってサーバー側でも必ず確認する。
まとめ
今回、特に覚えておきたいのは次の5つです。
- ミドルウェアで未ログインと権限不足を区別する
- カスタムミドルウェアは別名を登録するとルートで簡潔に指定できる
- ログイン後の画面振り分けだけでなく、ルート側でも認可する
-
UserとTaskはhasMany()とbelongsTo()の1対多関係 - タスクの更新・削除時は、所有者または管理者かをサーバー側で確認する