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

【Laravel12】UserモデルのPolicyが403になったので、AppServiseProviderの登録を見直した話

1
Posted at

はじめに

Laravelでダイアリー共有アプリを制作している中で、初心者ながら学んだことをアウトプットしていきたいと思います。初心者🔰につき、至らない点が多々あるかもしれませんが、何卒。

本記事の動作環境

  • Laravel 12.25.0
  • Docker + Laravel Sailを使用
  • macOS (M1)

やりたいこと

ユーザーのフォロー機能に続き、次にブロック機能を実装中。
今回、

「ブロックされているユーザーは、ブロックしたユーザーのプロフィール画面を見ることができない」

をLaravelの Policy(ポリシー) を使って実現したい。

試したこと

app/Policies/UserPolicy.phpを作り、プロフィール表示を判断するviewメソッドを書きます。
(コマンドの頭に./vendor/bin/sailがつきますが、省略しています)

php artisan make:policy UserPolicy
UserPolicy.php
    public function view(User $currentUser, User $profileUser)
    {
        // プロフィールの持ち主が、見ようとしているユーザーをブロックしているか?
        return !$profileUser->blocks()->where('users.id', $currentUser->id)->exists();
    }
  • $currentUser ...今ログインしているユーザー
  • $profileUser...プロフィールの持ち主

なお、blocks()は、Userモデルに定義した「ブロックしているユーザーを取得するためのリレーション」 です。

続いて、コントローラ側でポリシーを適用します。

UserProfileController.php
    public function show(User $user)
    {
        Gate::authorize('view', $user);
        
        // 省略

        return view('user_profile.show', compact('user'));
    }

これで実際にプロフィール画面にアクセスしたところ、ブロックされていないユーザーも含め、すべてのユーザーが 403 になり、見られなくなりました。

原因

原因はシンプルで、

UserモデルUserPolicyAppServiceProviderで紐付けていませんでした。

一方で、フォロー機能を実装した際に登録した、UserモデルとUserFollowPolicyの対応づけがありました。

AppServiceProvider.php
    public function boot(): void
    {
        // Policyの登録。UserモデルとUserFollowPolicyの対応づけ。
        Gate::policy(User::class, UserFollowPolicy::class);
    }

userモデルに紐づいたPolicyUserFollowPolicyだけで、そこにviewメソッドがないため、全員に403が返ってきていたようです。

解決策

AppServiceProviderUserモデルとUserPolicyの対応づけを行いました。

AppServiceProvider.php
    public function boot(): void
    {
        // Policyの登録。UserモデルとUserPolicyの対応づけ。
        Gate::policy(User::class, UserPolicy::class);
    }

また、同じUserモデルに2つのPolicyを登録することになるため、UserFollowPolicyの紐付けは削除し、中にあったfollow/unfollowメソッドはUserPolicyに統合しました。

これで、

「ブロックされているユーザーは、ブロックしたユーザーのプロフィール画面を見ることができない」

を実現することができました。

おわりに

Policyの登録を調べると概ねAuthServiceProviderに登録するように書いてあります。
しかし、ワタシの環境Laravel12では、デフォルトでAuthServiceProviderが存在せず、Policyの登録は、AppServiceProviderに登録するようです。
公式ドキュメントでも、「ポリシーの手作業による登録」として、以下のような記述があります。

Gateファサードを使用すると、アプリケーションの AppServiceProviderのbootメソッド内で、ポリシーと対応するモデルを手作業で登録できます。

モデル名とポリシーが命名規則に従っていれば、Laravelが自動的に紐付けを行うので、手作業で登録する必要はありません。

今回のようにフォロー・ブロック機能では、対象モデルがUserのため、Policyメソッドの引数がUserUserになるので、ややこしかったです。

同じようにつまづく方の参考になれば幸いです。

参考

記事の書き方は@Sicut_studyさんの以下を参考にさせていただきました。

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