タイトル: 管理者ユーザーの作成/判定と管理画面
SEOタイトル: Laravel で管理者ユーザーを作る方法 (is_admin / roles / Gate / Middleware
この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong>最小実装</strong>: <code>users</code> テーブルに <code>is_admin</code> カラムを追加</li><li><strong>柔軟な実装</strong>: <code>roles</code> / <code>role_user</code> テーブルで多対多 → Spatie Laravel-Permission</li><li><strong>判定</strong>: <code>Gate::define</code> + <code>@can("admin")</code> Blade ディレクティブ</li><li><strong>ルート保護</strong>: <code>middleware(["auth", "admin"])</code></li><li><strong>管理画面</strong>: Filament / Backpack / Voyager から選ぶ</li></ul></td></tr></table>
<h2>最小実装: is_admin カラム</h2>
<p>Laravel で 1 種類しか管理者がいない(一般 / 管理者の 2 値)場合の最速パターン:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// database/migrations/xxxx_add_is_admin_to_users.php
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('is_admin')->default(false)->after('email');
});
}
// User モデル
class User extends Authenticatable
{
protected $casts = [
'is_admin' => 'boolean',
];
public function isAdmin(): bool
{
return (bool) $this->is_admin;
}
}</code></pre>
<h2>判定: Gate</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// app/Providers/AuthServiceProvider.php
public function boot(): void
{
Gate::define('admin', function (User $user) {
return $user->isAdmin();
});
Gate::define('manage-articles', function (User $user) {
return $user->isAdmin() || $user->hasRole('editor');
});
}
// コントローラで利用
public function destroy(Article $article)
{
Gate::authorize('admin'); // 失敗時 403
$article->delete();
return redirect('/admin/articles');
}
// もしくは
if (Gate::allows('admin')) { ... }
if ($request->user()->can('admin')) { ... }</code></pre>
<h2>判定: Blade @can</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">{{-- resources/views/layouts/app.blade.php --}}
<nav>
<a href="/">トップ</a>
@auth
<a href="/mypage">マイページ</a>
@can('admin')
<a href="/admin">管理画面</a>
@endcan
<form action="/logout" method="post">
@csrf
<button>ログアウト</button>
</form>
@else
<a href="/login">ログイン</a>
@endauth
</nav></code></pre>
<h2>ルート保護: Middleware</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-bash">php artisan make:middleware AdminMiddleware</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// app/Http/Middleware/AdminMiddleware.php
public function handle(Request $request, Closure $next): Response
{
if (!$request->user() || !$request->user()->isAdmin()) {
abort(403, '管理者権限が必要です');
}
return $next($request);
}
// app/Http/Kernel.php (Laravel 10 まで)
protected $middlewareAliases = [
'admin' => \App\Http\Middleware\AdminMiddleware::class,
];
// bootstrap/app.php (Laravel 11+)
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'admin' => \App\Http\Middleware\AdminMiddleware::class,
]);
})
// routes/web.php
Route::middleware(['auth', 'admin'])->prefix('admin')->group(function () {
Route::get('/', [AdminController::class, 'index']);
Route::resource('users', \App\Http\Controllers\Admin\UserController::class);
});</code></pre>
<h2>多役割パターン: roles テーブル</h2>
<p>管理者・編集者・閲覧者など複数の役割が必要なら、<strong>roles</strong> + <strong>role_user</strong> の多対多にする:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// migration
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name')->unique(); // admin, editor, viewer
$table->string('display_name');
$table->timestamps();
});
Schema::create('role_user', function (Blueprint $table) {
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->foreignId('role_id')->constrained()->cascadeOnDelete();
$table->primary(['user_id', 'role_id']);
});
// User モデル
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}
public function hasRole(string $name): bool
{
return $this->roles->contains('name', $name);
}
public function isAdmin(): bool
{
return $this->hasRole('admin');
}</code></pre>
<h2>Spatie Laravel-Permission (推奨)</h2>
<p>自前で roles/permissions を作るより<strong>Spatie のパッケージ</strong>が圧倒的に楽:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-bash">composer require spatie/laravel-permission
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrate</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// User モデル
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable {
use HasRoles;
}
// 役割と権限の作成
$role = Role::create(['name' => 'admin']);
$permission = Permission::create(['name' => 'edit articles']);
$role->givePermissionTo($permission);
// 付与
$user->assignRole('admin');
$user->givePermissionTo('edit articles');
// 判定
$user->hasRole('admin');
$user->can('edit articles');
// Middleware
Route::middleware(['role:admin'])->group(...);
Route::middleware(['permission:edit articles'])->group(...);</code></pre>
<h2>管理者アカウントの作成 (Seeder)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// database/seeders/AdminUserSeeder.php
public function run(): void
{
User::firstOrCreate(
['email' => 'admin@example.com'],
[
'name' => 'Admin',
'password' => bcrypt('S3curePassw0rd!'),
'is_admin' => true,
]
);
}
// DatabaseSeeder.php
$this->call(AdminUserSeeder::class);
// 実行
// php artisan db:seed
// 本番では Artisan コマンド経由がおすすめ</code></pre>
<h2>管理画面パッケージ比較</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>パッケージ</th><th>特徴</th><th>向いてる用途</th></tr></thead>
<tbody>
<tr><td><strong>Filament</strong></td><td>Livewire ベース。最新・高機能。Resource 自動生成</td><td>新規プロジェクト・複雑な管理画面</td></tr>
<tr><td><strong>Laravel Nova</strong></td><td>公式有償。$199/site。安定</td><td>商用・サポート重視</td></tr>
<tr><td><strong>Backpack</strong></td><td>有償あり。CRUD パネル特化</td><td>シンプルな CRUD 中心</td></tr>
<tr><td><strong>Voyager</strong></td><td>無償。GUI で完結。メンテ停滞気味</td><td>WordPress ライクな感覚</td></tr>
<tr><td><strong>自前で作る</strong></td><td>Bootstrap / Tailwind + Blade</td><td>カスタム要件が強い場合</td></tr>
</tbody>
</table>
<h2>Filament を入れる例</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-bash">composer require filament/filament
php artisan filament:install --panels
php artisan make:filament-user</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// User モデルに FilamentUser を実装
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
class User extends Authenticatable implements FilamentUser
{
public function canAccessPanel(Panel $panel): bool
{
return $this->isAdmin();
}
}</code></pre>
<h2>FAQ</h2>
<p><strong>Q: <code>is_admin</code> と <code>roles</code> どちらを使うべき?</strong><br />
A: ユーザー数少 + 役割 2 種類なら <code>is_admin</code>。役割が増える / 権限が細かいなら Spatie 一択。</p>
<p><strong>Q: 管理画面の URL は隠すべき?</strong><br />
A: <code>/admin</code> 自体は隠しても効果薄。<strong>強パスワード + 2FA + IP 制限</strong>を組み合わせるのが本筋。</p>
<p><strong>Q: 管理者の操作ログを残したい</strong><br />
A: Spatie <code>laravel-activitylog</code> パッケージで Eloquent モデルの変更を自動記録。</p>