Laravel の authorizeResource()
を使って認可の実装をしようと思ったとき、index ページの403エラーが消えなくなって困ったことがあったからここに書いておく。
環境
- Laravel 6.x
authorizeResource() とは
例えば、とあるCRUDアプリケーションに記事投稿用のコントローラがあったとする。
アクションごとに権限を変えたりしたいときには、Policy を使って認可すると思う。
public function show(Request $request, Post $post)
{
$this->authorize('view', $post);
// 処理を書く
}
public function create(Request $request)
{
$this->authorize('create', Post::class);
// 処理を書く
}
public function update(Request $request, Post $post)
{
$this->authorize('create', $post);
// 処理を書く
}
.....しかし、いちいち $this->authorize('xxxx', xxxx);
と書くのは面倒くさい。
こんなときに authorizeResource()
が使える。
コンストラクタに下記のように書けば、$this->authorize('xxxx', xxxx);
の記述なしで自動で各アクションごとの Policy を見に行ってくれる。
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
※authorizeResource()
はリソースコントローラを使用しているときのみ使用可能
authorizeResource() の罠 (Laravel6.x~)
index アクションは認可を必要としていないはずなのに、index ページにいくと、403エラーになっていた。
結論から書くと、今回かかった罠は Laravel6.x アップグレードガイドに書かれていた。
authorizeResourceメソッドを用いてコントラーへ付加している認可ポリシーは、viewAnyメソッドを定義する必要があります。コントローラのindexメソッドへユーザーがアクセスする時に呼び出されます。定義しないと非認可扱いとなり、コントローラのindexメソッドへの呼び出しは拒否されます。
Laravel6.x アップグレードガイド 認可リソースとviewAny より
index アクションの認可が不要なときも、Policy に index アクション用のメソッド viewAny()
を書かなければいけなくなったのだ。
class PostPolicy
{
public function viewAny(User $user)
{
return true;
}
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
viewAny()
メソッドが定義されていない場合、非認可扱いとなり、私の時と同じように index ページで403エラーとなる。
※ Policy のアクション名は index
でなく、viewAny()
なことに注意
メソッド名対応表
コントローラメソッド | ポリシーメソッド |
---|---|
index | viewAny |
show | view |
create | create |
store | create |
edit | update |
update | update |
destroy | delete |
まとめ
- Laravel 6.x 以上で
authorizeResource()
を使っている人は気を付ける - アップグレードガイドはよく読む