1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Laravelのゲートを使用してみた

Last updated at Posted at 2021-04-30

Laravelには認証に加えて認可も手軽に実装できる方法を提供しています。Laravelの認可には「ゲート」と「ポリシー」の2つが用意されています。今回は「ゲート」を利用して特定のユーザーのアクションを制御しみます。

「ポリシー」についてはこちらの記事で解説しています。

ゲートを利用するために、サクッと認証を用意するには下記の記事を参考に。

ゲートの作成

App\Providers\AuthServiceProviderクラスに処理を追加します。例では、各記事の更新ページは、ログインしているユーザーが作成したページのみ表示できるようにしています。

app/Providers/AuthServiceProvider.php
namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use App\Models\Article;
use App\Models\User;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        // 'App\Models\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Gate::define('update-article', function (User $user, Article $article) {
            return $user->id === $article->user_id;
        });
    }
}

厳密な型の比較でusersテーブルのidとarticlesテーブルのuser_idを比較しています。ここで少しハマりポイントなのですが、articlesテーブルのuser_idをint型で定義していてもmodelではstringとして扱われてしまうので、この比較ではすべてfalseが返ってしまします。ですので、型をあわせるためにarticleモデルのほうでuser_idをintにキャストします。

app/Models/Article.php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasFactory;

    protected $guard = ['id'];

    protected $casts = [
        'user_id' => 'integer'
    ];
}

ゲートの利用

AuthServiceProviderで定義したゲートを利用してアクションを認可してみます。ArticlesControllerからゲート認可メソッドを呼び出して、認証済みユーザーが自身が作成したページ以外の記事更新ページをリクエストしたら403を返すようにします。

app/Http/Controllers/ArticlesController.php
namespace App\Http\Controllers;

use App\Models\Article;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;

class ArticlesController extends Controller
{
    // 更新メソッドなど

    public function edit(Article $article)
    {
        if (! Gate::allows('update-article', $article)) {
            abort(403);
        }

        return view('articles.edit', ['article' => $article]);
    }
}

特定のユーザーにはすべてのページを見れるようにする

例えば、一般ユーザーは自身が作成したページのみしか更新できないようにして、管理者はすべてのページを更新可能にしたいことがあるかと思います。「ゲートチェックの割り込み」を利用することによってこの機能を実現できるようになります。ゲートチェックの割り込みはすべての認可メソッドの前後に挟むことができます。今回はすべての認可メソッドの前に割り込みし、「admin」ロールが付与されたユーザーはすべての更新ページを見れるようにします。

usersテーブルにroleカラムを追加

まずはmigrationを利用してusersテーブルにroleカラムを追加します。usersテーブルを作成するマイグレーションファイルはlaravelのインストール時に含まれているので、カラム追加用のマイグレーションファイルを用意します。

php artisan make:migration add_role_to_users_table --table=users

マイグレーションファイル

xxxx_xx_xx_xxxxxx_add_role_to_users_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddRoleToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('role', 16)
                ->after('password')
                ->default('user');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('role');
        });
    }
}

作成したマイグレーションファイルを実行します。

php artisan migrate

usersテーブルにroleカラムが追加されました。任意のユーザーのroleをadminに変更します。

UPDATE users SET role='admin' WHERE id=3

これで一般ユーザーと管理者ユーザーが作成できました。

割り込み処理を追加

Gateファサードのbeforeメソッドを使用することで、すべての認可チェックの前に特定の処理を実行できます。今回は認証済みユーザーのroleがadminの場合にアクションを許可するようにします。

app/Providers/AuthServiceProvider
namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use App\Models\Article;
use App\Models\User;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        // 'App\Models\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Gate::before(function ($user, $ability) {
            if ($user->role === 'admin') {
                return true;
            }
        });

        Gate::define('update-article', function (User $user, Article $article) {
            return $user->id === $article->user_id;
        });
    }
}

これによって、adminロールが付与されたユーザーは自身が作成したページ以外のページも見れるようになります。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?