LoginSignup
0
0

【Laravel6.x】ポリシークラスの手順

Last updated at Posted at 2024-04-25

問題

ポリシークラス(認証処理)を使って
「権限のないコンテンツ」として403エラーを返したい!

手順

⓪ルートモデルバインディング
①ポリシークラスを作成
②ポリシークラスの中身を編集
③App/Providers/AuthServiceProviderを修正
④web.phpでミドルウェアを使用

⓪ルートモデルバインディング

index.blade.php
<a href="{{ route('spending.show', ['id' => $spending['id']]) }}" class="btn btn-info text-white btn-responsive">詳細</a>
↓
↓ // view(index.blade.php)とルーティングのパラメータをモデル名(spending)を合わせる
↓ // リソースコントローラーならターミナルで「php artisan route:list」を叩き、「Name」に記載されている
↓
<a href="{{ route('spending.show', ['spending' => $spending['id']]) }}" class="btn btn-info text-white btn-responsive">詳細</a>
SpendingController.php
// public function show(int $id)
// ↓ ⭐️修正
public function show(Spending $spending)
{
    // ⭐️ルートモデルバインディングのため削除
    // user所持か否かはポリシークラスで判別
    // $spending = Auth::user()->spending()->find($id);

    // ⭐️ルートモデルバインディングのため削除
    // URLでユーザーが所持しないidを入力された時に表示
    // if(is_null($spending)) {
    //    abort(404);
    // }

    return view('original.spending.show', [
        'spending' => $spending,
    ]);
}

public function edit(Spending $spending)
{
    // $spending = Auth::user()->spending()->find($id);

    // その他処理は省略
}

public function update(CreateData $request, Spending $spending)
{
    // $record = Auth::user()->spending()->find($id);

    // その他処理は省略
}

public function destroy(Spending $spending)
{
    // $record = Auth::user()->spending()->find($id);

    // その他処理は省略
}

【解説】
ルートモデルバインディング = ルーティング時点でインスタンスを取得しメソッドに渡す処理
ルーティングにID値を渡すと、find($id)の結果を渡してくれる

要するに

public function show(int $id)
{
    $spending = Auth::user()->spending()->find($id);

上記コードのようにshow関数に届いたidをfind()メソッドを使って該当情報を探していた処理を

index.blade.php
<a href="{{ route('spending.show', ['spending' => $spending['id']]) }}" class="btn btn-info text-white btn-responsive">詳細</a>
web.php
Route::resource('/spending', 'SpendingController');
(リソースコントローラーなので変更なし)
(リソースコントローラーならターミナルでphp artisan route:listを叩き、「Nameに記載されているバインディングを使う)
SpendingController.php
public function show(Spending $spending)
{

上記のaタグ→ルーティング→コントローラーの該当箇所を修正すれば
ルーティング時点でfind($id)やってくれるようになっているということ

※注意
現在のユーザー情報は取得していないため
ログインユーザー以外の情報も取得できてしまう。
例えばURLに直接他社ユーザーの情報を入力すると取得できてしまう。

そのためポリシークラスで

$spending = Auth::user()->spending()->find($id);

の、Auth::user()->spending()の部分のような認証処理をつけていく

①ポリシークラスを作成

ポリシークラス = 権限認可の処理を管理する

ターミナル

php artisan make:policy SpendingPolicy --model=Spending

「App/Policies」ディレクトリが生成されて、ファイルも生成される

②ポリシークラスの中身を編集

App/Policies/SpendingPolicy.php
public function view(User $user, Spending $spending)
{
    return $user->id === $spending->user_id;
}

【解説】
ファイル内にはデフォルトで複数の関数がある
閲覧や更新などどのように認可をするか細かく設定ができる
上記はviewにまとめて設定してある

view関数の引数には
・第一引数でUserのインスタンス
・第二引数で対象とするモデル(Spending)のインスタンス

戻り値はbool型
true→許可、false→拒否

③App/Providers/AuthServiceProviderを修正

App/Providers/AuthServiceProvider.php
protected $policies = [
    // 'App\Model' => 'App\Policies\ModelPolicy',
    'App\Spending' => 'App\Policies\SpendingPolicy',
];

【解説】
$policies内に「モデル=>紐づけるポリシー」で設定
これによって「Spendingモデルに関する処理はSpendingPolicyを通す」ということになる

④web.phpでミドルウェアを使用

web.php
  //支出ルート以外は省略

Route::group(['middleware' => 'auth'], function() {
  // 支出登録
  // ⭐️create、storeは、引数でidを必要としないためUser->とSpending->idの一致を確認するポリシークラスで弾かれてしまう
  // そのため「create」「store」のみ外側&先に処理する 
  // ポリシークラスではexceptをしっかり記述
  Route::resource('/spending', 'SpendingController', ['only' => ['create', 'store']]);

  // ⭐️ポリシークラス
  Route::group(['middleware' => 'can:view,spending'], function() {
    // 支出登録、支出詳細、支出削除、支出編集
    Route::resource('/spending', 'SpendingController', ['except' => ['create', 'store']]);
  });
});

【解説 ⭐️ポリシークラス】
canミドルウェア = 引数の認可処理を見て、trueを返せば処理を進め、falseなら403(権限)エラーを返す
view = 今回使用するポリシーの関数
spending = バインディングしているルートのパラメータ

パラメータからモデル(Spending)を判断し、使用するポリシーの関数(view)を参照している

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