0
0

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 5 years have passed since last update.

Laravelのポリシーを使用してみた

0
Posted at

Laravelには認可機能として「ゲート」と「ポリシー」が用意されています。

「ゲート」は下記の記事で試してみたので、今回は「ポリシー」を試してみます。

ポリシーの生成

artisanコマンドでポリシーを生成できます。--modelオプションを使用すればモデルに関連付けたポリシーを生成することができます。

php artisan make:policy ArticlePolicy --model=Article

artisanコマンドを実行するとapp/Policiesディレクトにファイルが生成されます。生成されたファイルにはいくつかのメソッドがあらかじめ作られています。

app/Policies/ArticlePolicy.php
<?php

namespace App\Policies;

use App\Models\Article;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class ArticlePolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can view any models.
     *
     * @param  \App\Models\User  $user
     * @return mixed
     */
    public function viewAny(User $user)
    {
        //
    }

    /**
     * Determine whether the user can view the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Article  $article
     * @return mixed
     */
    public function view(User $user, Article $article)
    {
        //
    }

    /**
     * Determine whether the user can create models.
     *
     * @param  \App\Models\User  $user
     * @return mixed
     */
    public function create(User $user)
    {
        //
    }

    /**
     * Determine whether the user can update the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Article  $article
     * @return mixed
     */
    public function update(User $user, Article $article)
    {
        //
    }

    /**
     * Determine whether the user can delete the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Article  $article
     * @return mixed
     */
    public function delete(User $user, Article $article)
    {
        //
    }

    /**
     * Determine whether the user can restore the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Article  $article
     * @return mixed
     */
    public function restore(User $user, Article $article)
    {
        //
    }

    /**
     * Determine whether the user can permanently delete the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Article  $article
     * @return mixed
     */
    public function forceDelete(User $user, Article $article)
    {
        //
    }
}

ポリシーを使用したアクションの認可

ここから、ポリシーを使用してユーザーにある操作の許可・拒否を実装していきます。例えば記事の更新は、記事を作成したユーザーのみしかできないようにしてみます。

app/Policies/ArticlePolicy.php
    /**
     * Determine whether the user can update the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Article  $article
     * @return mixed
     */
    public function update(User $user, Article $article, $category, $role)
    {
        return $user->id === $article->user_id;
    }

定義したアクションは、

  • ユーザーモデル経由
  • コントローラヘルパ経由
  • ミドルウェア経由
  • Bladeテンプレート経由

で呼び出せます。

ユーザーモデル経由

App\Models\Userモデルにはアクションを認可するための特別なメソッドcancannotが含まれていて、これらのメソッドを使用することでアクションを認可することができます。

app/Http/Controllers/ArticlesController.php
    public function edit(Request $request, Article $article)
    {
        if ($request->user()->cannot('update', $article)) {
            abort(403);
        }

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

コントローラヘルパ経由

コントローラからauthorizeメソッドを呼び出すことによっても、アクションを認可することができます。

app/Http/Controllers/ArticlesController.php
    public function edit(Request $request, Article $article)
    {
        $this->authorize('update', $article);

        return view('articles.edit', $article);
    }

ミドルウェア経由

canミドルウェアを使用することで、アクションの認可ができます。

routes/web.php
Route::get('/article/edit/{article}', 'App\Http\Controllers\ArticlesController@edit')
    ->middleware(['auth'])
    ->middleware('can:update,article');

Bladeテンプレート経由

bladeテンプレート内で@canまたは@cannotディレクティブを使用することで、アクションを認可できます。

edit.blade.php
@can('update', $article)
<input type="submit" value="send">
@else
<h3>更新できません</h3>
@endcan

ポリシーフィルター

ポリシーファイルでbeforeメソッドを定義すると、ほかのポリシーメソッドが呼び出される前に実行されます。例えばadminユーザーはすべてのアクションを許可したいとなった場合、

app/Policies/ArticlePolicy.php
    public function before(User $user, $ability)
    {
        if ($user->role === 'admin') {
            return true;
        }
    }

このように定義するとadminユーザーをすべてのアクションが許可されます。

ポリシーメソッドに追加のパラメータを渡す

例えば、あるカテゴリーの記事に関してはすべてのユーザーが更新できるようにしたいとなった場合、

ArticlePolicy.php
    /**
     * Determine whether the user can update the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Article  $article
     * @return mixed
     */
    public function update(User $user, Article $article, $category)
    {
        return $user->id === $article->user_id || $category === 'free';
    }

このように、updateメソッドの第3引数に$categoryを追加します。ポリシーを呼び出す側では、

ArticlesController.php
    public function edit(Request $request, Article $article)
    {
        $this->authorize('update', [$article, $request->category]);

        return view('articles.edit', $article);
    }

このように、最初の引数にアクション名を渡し2番目の引数に配列を渡します。配列の1番目には、どのポリシーを使用するかを指定し、2番目以降にポリシーメソッドに渡すパラメータを指定します。

おまけ

ポリシーを使用するにあたって、認証機能・必要なテーブルデータを用意する必要がある場合は下記の記事を参考に。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?