質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

1153閲覧

Laravel 認可(Policy)の反映がうまくいきません

jirou6699

総合スコア4

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2022/08/07 04:19

編集2022/08/07 16:24

やりたいこと

laravelでpolicyを使った認可処理でつまづいています。
投稿(create)した本人しか更新できない(update)ようにしたいのですが、誰でも更新できるような状態になってしまいます。他の質問者様の内容や記事も参考にしましたが、どうもうまくいっていない状況です。アドバイス等いただければ嬉しいです。

やってみたこと

主に公式ドキュメントを参考にpolicyを作成しています。

ポリシーの生成

ポリシー名はモデル名と同じにするよう、contactFormPolicyとしました。

PHP:app/Policies/ContactFormPolicy.php

1 /** 2 * Determine whether the user can update the model. 3 * 4 * @param \App\Models\User $user 5 * @param \App\Models\ContactForm $contactForm 6 * @return \Illuminate\Auth\Access\Response|bool 7 */ 8 public function update(User $user, ContactForm $contactForm) 9 { 10 return $user->id === $contactForm->user_id; 11 } 12

ポリシーの登録

PHP:app/Providers/AuthServiceProvider.php

1namespace App\Providers; 2 3// use Illuminate\Support\Facades\Gate; 4 5use App\Models\ContactForm; 6use App\Policies\ContactFormPolicy; 7use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; 8 9class AuthServiceProvider extends ServiceProvider 10{ 11 /** 12 * The model to policy mappings for the application. 13 * 14 * @var array<class-string, class-string> 15 */ 16 protected $policies = [ 17 // モデル名 => モデルポリシー名 18 ContactForm::class => ContactFormPolicy::class 19 ]; 20 21 /** 22 * Register any authentication / authorization services. 23 * 24 * @return void 25 */ 26 public function boot() 27 { 28 $this->registerPolicies(); 29 30 // 31 } 32}

アクション認可

contactFormコントローラーのupdateメソッドにauthorizeメソッドを使用して、投稿(create)した同一ユーザーのみ編集(update)できるようにしたつもりです。

PHP:

1 /** 2 * Update the specified resource in storage. 3 * 4 * @param \Illuminate\Http\Request $request 5 * @param int $id 6 * @return \Illuminate\Http\Response 7 */ 8 public function update(Request $request, $id, ContactForm $contactForm) 9 { 10 $contact = ContactForm::find($id); 11 $contact->name = $request->your_name; 12 $contact->title = $request->title; 13 $contact->email = $request->email; 14 $contact->url = $request->url; 15 $contact->gender = $request->gender; 16 $contact->age = $request->age; 17 $contact->contact = $request->contact; 18 $this->authorize('update', $contactForm);   //←ここにアクション処理の認可設定 19 $contact->save(); 20 return redirect() 21 ->route('contact.index'); 22 }

結果

イメージ説明

考えたこと・思ったこと

今回はuserとcontactformを1対多の関係でリレーションし、ダミーデーターを入れて動かしています。
policy自体は動いてくれてるので、idと紐づいていない可能性があると思っていますがsqlにもデータが入っているので自分でおかしいポイントを把握できていません。

ER図

イメージ説明

sql(カラム)

イメージ説明

sql(データ)

イメージ説明

よろしくお願いします。

ルーティング

PHP:routes/web.php

1Route::group(['prefix'=>'contact','middleware'=>'auth'], function(){ 2 Route::get('index', [ContactFormController::class ,'index'])->name('contact.index'); 3 Route::get('create', [ContactFormController::class ,'create'])->name('contact.create'); 4 Route::post('store', [ContactFormController::class ,'store'])->name('contact.store'); 5 Route::get('show/{id}/', [ContactFormController::class, 'show'])->name('contact.show'); 6 Route::get('edit/{id}/', [ContactFormController::class, 'edit'])->name('contact.edit'); 7 Route::post('update/{id}/', [ContactFormController::class, 'update'])->name('contact.update'); 8 Route::post('destroy/{id}/', [ContactFormController::class, 'destroy'])->name('contact.destroy'); 9 });

解決

アドバイスをもとに下記修正したところ、想定通りの動きができました。

ルーティング

アクションを全て記載していたので、resourcesに変更してコードをスッキリしました。

PHP:routes/web.php

1Route::group(['middleware'=>'auth'], function(){ 2 Route::resource('contact', ContactFormController::class, 3);

コントローラーの記載

こちらの記事を参考にフィルを使う場合の記載に変更しました。結局authorizeを使用した方法しか今はわかりませんでしたが、authorizeの第二引数の使い方が良くないことは理解できました。またルーティングをresourceにすると、updateメソッドで$idを使用しないと値をとれませんでした。
ただ、これで投稿ユーザーしか編集ができないように設定することができました!
fillを使ったカラムの登録

PHP

1 public function update(Request $request, $id) 2 { 3 4 $contact = ContactForm::find($id); 5 $this->authorize('update', $contact); //authorizeを使用した認可 6 $contact->fill([ 7 'name' => $request->your_name, 8 'title' => $request->title, 9 'email' => $request->email, 10 'url' => $request->url, 11 'gender' => $request->gender, 12 'age' => $request->age, 13 'contact' => $request->contact, 14 ]); 15 $contact->save(); 16 return redirect() 17 ->route('contact.index');

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

コントローラの実装がおかしいです。
ルーティングが提示されていないので、PUTで定義されていることを前提で回答しています。

diff

1- public function update(Request $request, $id, ContactForm $contactForm) 2+ public function update(Request $request, ContactForm $contactForm) 3 { 4- $contact = ContactForm::find($id); 5// name <- your_name と名称違うので、個別に設定しているけど、同じ名前なら 6// $contact->fill($request->all())->save(); と書ける 7+ $contact->fill([ 8+ 'name' => $request->your_name, 9+ 'title' => $request->title, 10+ 'email' => $request->email, 11+ 'url' => $request->url, 12+ 'gender' => $request->gender, 13+ 'age' => $request->age, 14+ 'contact' => $request->contact, 15+ ]); 16- $contact->name = $request->your_name; 17- $contact->title = $request->title; 18- $contact->email = $request->email; 19- $contact->url = $request->url; 20- $contact->gender = $request->gender; 21- $contact->age = $request->age; 22- $contact->contact = $request->contact; 23- $this->authorize('update', $contactForm);   //←AuthServiceProvider にマッピングしているので、これ不要 24 $contact->save(); 25 return redirect() 26 ->route('contact.index'); 27 }

ここから追記

php

1 public function update(User $user, ContactForm $contactForm) 2 { 3 dd($user, $contactForm); // ここで値を確認する 4 return $user->id === $contactForm->user_id; 5 }

投稿2022/08/07 06:13

編集2022/08/07 12:02
phper.k

総合スコア3923

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jirou6699

2022/08/07 09:02

早速ご回答ありがとうございます。 今回は通常のupdate処理は正しく処理できているんですが、 policyを使って他ユーザーが投稿した内容を勝手に更新できないようにしたいと考えていました。 また、authorizeを入れないと投稿したユーザーとは別のユーザーが編集とするとその判定されず、 認可の処理がされないように思います、どうでしょうか? ご指摘の通り、下記の通り試しておりますが更新内容が反映されないようになってしまします、、、、、 ご確認いただけますでしょうか? ①ルーティングはPUSTではなく、updateもPOSTで設定していました。 ``` Route::group(['prefix'=>'contact','middleware'=>'auth'], function(){ Route::get('index', [ContactFormController::class ,'index'])->name('contact.index'); Route::get('create', [ContactFormController::class ,'create'])->name('contact.create'); Route::post('store', [ContactFormController::class ,'store'])->name('contact.store'); Route::get('show/{id}/', [ContactFormController::class, 'show'])->name('contact.show'); Route::get('edit/{id}/', [ContactFormController::class, 'edit'])->name('contact.edit'); Route::post('update/{id}/', [ContactFormController::class, 'update'])->name('contact.update'); Route::post('destroy/{id}/', [ContactFormController::class, 'destroy'])->name('contact.destroy'); }); ``` 今回のご指摘を受け、下記のように変更しました。formの中に @method('PUT')も追記しています。 ``` Route::put('update/{id}/', [ContactFormController::class, 'update'])->name('contact.update'); ``` ②コントローラーも下記のように変更しています。 ``` public function update(Request $request, ContactForm $contactForm) { $contactForm->fill([ 'name' => $request->your_name, 'title' => $request->title, 'email' => $request->email, 'url' => $request->url, 'gender' => $request->gender, 'age' => $request->age, 'contact' => $request->contact, 'user_id' => Auth::id(), ]); $contactForm->save(); return redirect() ->route('contact.index'); } ```
phper.k

2022/08/07 12:31 編集

追記を参考に値を確認してください。 あとルーティングは、 Route::resource(); を使った方がいいですね
jirou6699

2022/08/07 16:27

アドバイスをもとに調べながら解決ができました。ありがとうございました! ただ下記の部分はまだ理解が浅いためか不要の方法がわからずですので、今後理解を深めていきます。 $this->authorize('update', $contactForm); //←AuthServiceProvider にマッピングしているので、これ不要
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問