FormRequest
の authorize()
は、リクエストが承認されるかどうかを決定するための重要なメソッドです。
しかしながら、いつもtrue
を返して使ってるよ!……という方も多いのではないでしょうか?
実は私もそうで、コマンドでFormRequest
を作成後、条件反射でfalse
からtrue
に書き変えてしまいます。
きっともっと有効な使い方があるハズ……と思い、authorize()
をマニュアルを読みつつ調べてみました。驚くような方法があったわけではありませんが、基本知識として得られるものがありました。
Laravel初心者にもわかりやすいように解説したいと思います。
authorize()の基本
このメソッドは、リクエストがバリデーションを受ける前に実行されます。returnによる戻り値として、true
または false
のいずれかを返す必要があります。
authorize()がtrueを返す場合の動作
public function authorize()
{
return true;
}
true
を返すことで、FormRequest
を実行する認可が得られたことを意味します。具体的には、何事も無かったかのようにそのまま処理が進みます。
その後、同クラス内にあるrules()
で定義するバリデーションを実行。そしてバリデーションが通った際は、改めてコントローラのメソッドを実行することになります。
authorize()がfalseを返す場合の動作
public function authorize()
{
return false;
}
authorize()
メソッドで false
を返すと、ユーザーがリクエストを実行するための認可が得られないことを示します。
この場合、Laravelは自動的に 403 Forbidden
レスポンスを生成してくれます。
要はアクセスを拒否してくれます。当然rules()
メソッドは呼ばれませんし、コントローラのメソッドも実行されません。
例えばLaravelをインストールしたての場合、以下のようなシンプルな403 Forbidden
のエラー画面が表示されます。
私もLaravel初心者のころ、この画面が出てしまいなぜなんだろう……という経験をした記憶があります。
初期状態のコード
以下のコマンドでFormRequest
の子クラスを作ったとします。
php artisan make:request TestRequest
この場合、以下の様にして当該メソッドは作成されています。
public function authorize()
{
return false;
}
先ほど説明したように、これではすべてのユーザーに対してリクエストを拒否してしまいます。つまりこのクラスを使えません。
おそらくはデフォルトでtrue
にすると、セキュリティ的に問題が発生する可能性を考えられてのことでしょう。
理解して使ってね、と、Laravelが親切でしてくれていることと考えられます。
よく使われる方法
初期状態のコードのままでは使えないので、メソッドの戻り値が条件によりtrue
になるように修正します。……が、以下の様に無条件でtrue
を返すようにするケースもめずらしくありません。
public function authorize()
{
// 無条件でtrueにして常に使えるようにする
return true;
}
このようにすれば、誰もが常に利用できるクラスになります。
例えば企業のお問い合せフォームのバリデーション時を考えてみます。誰でもお問い合せを送信できるようにするのが普通なので、このように無条件でtrue
を返す設定にすることが通常です。
応用編
すでに書いているとおり、authorize()
は、特定の条件に基づいてリクエストを許可 or 拒否するための認可ロジックを含めることができます。
しかしながら、初心者の内は具体的にどういう例があるのか想像しづらいことでしょう。
そこでここでは「こんな風に使えるよ!」というコード例を挙げてみました。あなたが作るWebアプリケーションで応用できそうなところがあれば参考にしてください。
依存注入の利用
authorize()
メソッドはLaravelのサービスコンテナ機能により、タイプヒントするだけで依存注入してくれます。以下では、6行目で、UserService
クラスを利用できるようにしています。
use App\Services\UserService;
use Illuminate\Support\Facades\Auth;
class CustomFormRequest extends FormRequest
{
public function authorize(UserService $userService): bool
{
$user = Auth::user();
return $userService->canUserPerformAction($user);
}
use文で指定するのをお忘れなく!
ユーザーロールに基づく認可
特定のユーザーのみがリクエストを許可される場合などで使えます。例えば、以下はログインユーザーが'admin'
、つまり管理者の場合のみ許可されます。
public function authorize()
{
return auth()->user()->role === 'admin';
}
カスタム権限/許可に基づく認可
カスタム権限システムやパーミッションベースのシステムを使用して、ユーザーに特定の許可がある場合のみリクエストを許可します。
例えば、記事の編集権限を持っているユーザーのみが許可される場合です。
public function authorize()
{
return auth()->user()->hasPermission('edit-posts');
}
リソースの所有者に基づく認可
例えば、ユーザーが自分のプロフィールを編集する際など、特定のリソースの所有者だけがリクエストを許可される場合。
public function authorize()
{
$profile = Profile::find($this->route('profile_id'));
return auth()->user()->id === $profile->user_id;
}
特定の時間に基づく認可
特定の時間帯にのみリクエストを許可する場合(例えば、営業時間内のみ使える社内アプリなど)。
public function authorize()
{
$currentHour = date('H');
return $currentHour >= 9 && $currentHour <= 17; // 9:00 から 17:00 まで
}
特定のIPアドレスからのリクエストのみを許可
特定のIPアドレスからのみ許可する場合。
public function authorize()
{
$allowedIps = ['192.168.1.1', '192.168.1.2'];
return in_array($this->ip(), $allowedIps);
}
こういった処理はFormRequest
で行うべきか、他のミドルウェア等で行うべきかは要検討ですね。
ユーザーの年齢に基づく認可
例えば、18歳以上のユーザーのみにリクエストを許可する場合。
public function authorize()
{
return auth()->user()->age >= 18;
}
まとめ
単純にtrue
を返すだけ……という使い方も多いですが、いろいろな使い方ができることが分かりました。
このメソッドはあまり手をつけないようにしていたのですが、意外と使い所はありそうです。
実際にはauthorize()
を使わずに同じ機能を実現できることも多いかもしれません。また、良くも悪くも一律で403エラーが出てしまうこともあります。
しかしながら、適切な場所(403エラーを出しても相応しい場所)では積極的に使っていきたいところですね。
コメント