Laravel認可における GateとPolicyの扱いについて

#はじめに
GateとPolicyの違いなどが理解しきれていなかったため、公式ドキュメントから理解したものを記載します。

参考
https://readouble.com/laravel/8.x/ja/authorization.html


#環境
・PHP 8.0.1
・Laravel 8.40.0

#画面構成
・routes/web.php

```
// TOP画面
Route::get('top', [ArticleController::class, 'index'])->name('top');
// 登録フォーム画面
Route::get('top/create', [ArticleController::class, 'create'])->name('top_create');
// 登録処理
Route::post('top/store', [ArticleController::class, 'store'])->name('top_store');
// 編集フォーム画面
Route::get('top/edit/{id}', [ArticleController::class, 'edit'])->name('top_edit');
// 編集処理
Route::post('top/update/{id}', [ArticleController::class, 'update'])->name('top_update');
// 削除処理
Route::get('top/destroy/{id}', [ArticleController::class, 'destroy'])->name('top_destroy');

```

#aritclesテーブル
aritclesテーブルのマイグレーションファイル

```
class CreateArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->id();
            $table->string('title');          // タイトル
            $table->text('note')->nullable(); // 内容
            $table->integer('user_id');       // 登録ユーザー
            $table->timestamps();
        });
    }
```


#認可とは
認可とはページにおけるアクセスできる権限です。
ユーザーの種別によってアクセスを許可と不許可に分けるようなことができます。

#Gate
ゲートはユーザーがアクションに認可(アクセス許可)できるか設定をします。

以下は、登録画面へのアクセスにGateで認可処理を設定します。

####1. 認可を設定します。

App\Providers\AuthServiceProvider

```
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('is-admin', function (User $user) {
            return $user->id === 1; // ユーザーテーブルのIDが1の場合のみ認可を与える。
        });
    }
}
```

####2. アクションにGateの認可処理を設定する。

app/Http/Controllers/ArticleController.php

```
class ArticleController extends Controller
{
    public function create()
    {
        // ログイン情報
        $user = Auth::guard('web')->user();

        // 認可されたユーザーのみ画面を表示する。それ以外はTOP画面へリダイレクトする。
        if(!Gate::allows('is-admin', $user)) {
            return redirect(route('top'));
        }

        return view('create');
    }
}
```

画面の一部分に認可されたユーザーのみ表示することも可能です。

resources/views/top.blade.php

```
<div>認可のチェック</div>

@can('is-admin')
認可されたユーザーのみ表示されます。
@endcan

```

#Policy
ポリシーは特定のモデルへの処理に実行許可を与える, もしくは禁止するようにできます。


####1. ポリシーを作成します。

```
php artisan make:policy ArticlePolicy --model=Article
```
Policyのファイルが作成されます。
　app/Policies/ArticlePolicy.php

####2.作成したPolicyの登録を行います。

App\Providers\AuthServiceProvider

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

####3. Policyの設定を行います。以下は更新処理へのポリシーになります。

```
class ArticlePolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can update the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Article  $article
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function update(User $user, Article $article)
    {
        // 更新処理を行いユーザーが登録したユーザーと同じ場合
        return $user->id === $article->user_id ? Response::allow() : Response::deny('更新を許可していません');;
    }
```

####4. コンローラー側にauthorizeで認可処理を設定します。

```
class ArticleController extends Controller
{

    public function update($id, UpdateRequest $request)
    {
        $article = Article::findOrFail($id);

        // 認可処理を設定
        $this->authorize('update', $article);

        $article->title = $request->title;
        $article->note = $request->note;
        $article->save();

        return redirect(route('top'));
    }
```

#現段階でのまとめ
・Gateはページや画面の一部分の表示・非表示に使う
・Policyはモデルに対しての処理(CRUDなど)行う

まだいろんな使い方はあるかもしれないですが、一旦初歩的なまとめということで。。