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

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

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

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

PHP

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

Q&A

解決済

2回答

6374閲覧

掲示板の投稿者のみ編集できるようにしたい(Laravel)

GO999

総合スコア5

Laravel

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

PHP

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

0グッド

0クリップ

投稿2019/12/21 14:40

編集2019/12/26 13:52

掲示板の投稿者のみ編集できるようにしたい(Laravel)

前提・実現したいこと

Laravelを使用して掲示板を作成しています。投稿者のみ投稿内容の編集・更新ができるようにしたいです。ログイン機能の実装は上手く行きましたが、投稿者であるにも関わらず投稿内容の編集が出来ない状態です。

発生している問題・エラーメッセージ

ポリシーを作成・登録し、userのid と postのuser_idが合致した場合のみ編集・更新できるように記述、コントローラでauthorizeによる認可を追加しました。しかし、投稿者かどうかに関わらず、編集ボタンを押すと403 This action is unauthorized.とブラウザに表示されてしまいます。

該当のソースコード

App/Http/Providers/AuthServiceProvider.php

PHP

1<?php 2 3namespace App\Providers; 4 5use App\Post; 6use App\Policies\PostPolicy; 7use App\User; 8use App\Policies\UserPolicy; 9use Illuminate\Support\Facades\Gate; 10use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; 11 12class AuthServiceProvider extends ServiceProvider 13{ 14 /** 15 * The policy mappings for the application. 16 * 17 * @var array 18 */ 19 protected $policies = [ 20 'App\Model' => 'App\Policies\ModelPolicy', 21 // 'App\Model' => 'App\Policies\ModelPolicy', 22 User::class => UserPolicy::class, 23 Post::class => PostPolicy::class, 24 ]; 25 26 /** 27 * Register any authentication / authorization services. 28 * 29 * @return void 30 */ 31 public function boot() 32 { 33 $this->registerPolicies(); 34 config(['admin_id' => 1]); 35 // 36 } 37} 38

App/Http/Policies/PostPolicy.php

PHP

1<?php 2 3namespace App\Policies; 4use App\Post; 5use App\User; 6use Illuminate\Auth\Access\HandlesAuthorization; 7 8class PostPolicy 9{ 10 use HandlesAuthorization; 11 12 /** 13 * Create a new policy instance. 14 * 15 * @return void 16 */ 17 public function __construct() 18 { 19 // 20 } 21 22 public function edit(User $user, Post $post) 23 { 24 return $user->id === $post->user_id; 25 } 26 27 public function update(User $user, Post $post) 28 { 29 return $user->id === $post->user_id; 30 } 31 32 33 34}

App/Http/Policies/UserPolicy.php

PHP

1<?php 2 3namespace App\Policies; 4 5use App\Post; 6use App\User; 7use Illuminate\Auth\Access\HandlesAuthorization; 8 9class UserPolicy 10{ 11 use HandlesAuthorization; 12 13 /** 14 * Create a new policy instance. 15 * 16 * @return void 17 */ 18 public function __construct() 19 { 20 // 21 } 22 23 public function edit(User $user, User $model) 24 { 25 return $user->id == $model->id; 26 } 27 28 public function update(User $user, User $model) 29 { 30 return $user->id == $model->id; 31 } 32}

App/Http/Controllers/PostsController.php

PHP

1<?php 2 3namespace App\Http\Controllers; 4 5use Illuminate\Http\Request; 6use App\Post; 7use App\Http\Controllers\Controller; 8class PostsController extends Controller 9{ 10 public function index() 11 { 12 return view('posts.top'); 13 14 } 15 16 public function bbs() 17 { 18 $posts = Post::with(['comments'])->orderBy('created_at', 'desc')->paginate(10); 19 return view('posts.bbs',['posts'=>$posts]); 20 } 21 22 public function create() 23 { 24 return view('posts.create'); 25 } 26 27 public function store(Request $request) 28 { 29 $params = $request->validate([ 30 'title' => 'required|max:50', 31 'body' => 'required|max:2000', 32 ]); 33 34 auth()->user()->posts()->create($params); 35 //Post::create($params); 36 37 return redirect()->route('bbsTop'); 38 } 39 40 public function show($post_id) 41 { 42 $post=Post::findOrFail($post_id); 43 44 return view('posts.show',[ 45 'post'=>$post, 46 ]); 47 } 48 49 public function edit($post_id) 50 { 51 52 $post=Post::findOrFail($post_id); 53 $this->authorize('edit', $post); 54 return view('posts.edit', [ 55 'post' => $post, 56 ]); 57 } 58 59 public function update($post_id,Request $request) 60 { 61 $params=$request->validate([ 62 'title'=>'required|max:50', 63 'body'=>'required|max:2000', 64 ]); 65 $post=Post::findOrFail($post_id); 66 $this->authorize('update', $post); 67 $post->fill($params)->save(); 68 return redirect()->route('posts.show',['post'=>$post]); 69 } 70 71 public function destroy($post_id) 72 { 73 $post=Post::findOrFail($post_id); 74 75 \DB::transaction(function() use ($post){ 76 $post->comments()->delete(); 77 $post->delete(); 78 }); 79 80 return redirect()->route('bbsTop'); 81 } 82 83 84 } 85

database/migrations/posts_table.php

PHP

1<?php 2 3use Illuminate\Support\Facades\Schema; 4use Illuminate\Database\Schema\Blueprint; 5use Illuminate\Database\Migrations\Migration; 6 7class CreatePostsTable extends Migration 8{ 9 /** 10 * Run the migrations. 11 * 12 * @return void 13 */ 14 public function up() 15 { 16 Schema::create('posts', function (Blueprint $table) { 17 $table->increments('id'); 18 $table->unsignedInteger('user_id'); 19 $table->string('title',50); 20 $table->text('body'); 21 $table->timestamps(); 22 23 $table->foreign('user_id')->references('id')->on('users'); 24 }); 25 } 26 27 /** 28 * Reverse the migrations. 29 * 30 * @return void 31 */ 32 public function down() 33 { 34 Schema::dropIfExists('posts'); 35 } 36}

database/migrations/users_table.php

PHP

1<?php 2 3use Illuminate\Support\Facades\Schema; 4use Illuminate\Database\Schema\Blueprint; 5use Illuminate\Database\Migrations\Migration; 6 7class CreateUsersTable extends Migration 8{ 9 /** 10 * Run the migrations. 11 * 12 * @return void 13 */ 14 public function up() 15 { 16 Schema::create('users', function (Blueprint $table) { 17 $table->bigIncrements('id'); 18 $table->string('name'); 19 $table->string('email')->unique(); 20 $table->timestamp('email_verified_at')->nullable(); 21 $table->string('password'); 22 $table->rememberToken(); 23 $table->timestamps(); 24 }); 25 } 26 27 /** 28 * Reverse the migrations. 29 * 30 * @return void 31 */ 32 public function down() 33 { 34 Schema::dropIfExists('users'); 35 } 36}

App/Http/Providers/Post.php

PHP

1<?php 2 3namespace App; 4 5use Illuminate\Database\Eloquent\Model; 6 7class Post extends Model 8{ 9 protected $fillable = [ 10 'title', 11 'body', 12 ]; 13 14 public function comments() 15 { 16 return $this->hasMany('App\Comment'); 17 } 18 19 public function user() 20 { 21 return $this->belongsTo('App\User'); 22 } 23} 24

App/Http/Providers/User.php

PHP

1<?php 2 3namespace App; 4 5use Illuminate\Notifications\Notifiable; 6use Illuminate\Contracts\Auth\MustVerifyEmail; 7use Illuminate\Foundation\Auth\User as Authenticatable; 8 9class User extends Authenticatable 10{ 11 use Notifiable; 12 13 /** 14 * The attributes that are mass assignable. 15 * 16 * @var array 17 */ 18 protected $fillable = [ 19 'name', 'email', 'password', 20 ]; 21 22 /** 23 * The attributes that should be hidden for arrays. 24 * 25 * @var array 26 */ 27 protected $hidden = [ 28 'password', 'remember_token', 29 ]; 30 31 /** 32 * The attributes that should be cast to native types. 33 * 34 * @var array 35 */ 36 protected $casts = [ 37 'email_verified_at' => 'datetime', 38 ]; 39 40 public function posts() 41 { 42 return $this->hasMany('App\Post'); 43 } 44 45 46} 47

試したこと

参照サイトを参考にポリシーの作成・登録、ルールの記述、コントローラに認可を追加しました。何度やっても上手くいかなかったので、Post.php,User.phpと、テーブルも確認し記述し直しましたが、投稿者IDとユーザーIDを合致させて認可することができませんでした。
参照サイト:https://readouble.com/laravel/5.7/ja/authorization.html#writing-policies
https://qiita.com/sutara79/items/11d8417a6fc91ca1b841
https://tech.windii.jp/backend/laravel/authorization-basic

補足情報(FW/ツールのバージョンなど)

Laravel Framework 5.8.35
DB SQLite

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

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

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

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

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

guest

回答2

0

ベストアンサー

PostsController の update メソッドの
$this->authorize('update', $post);
は、
$this->authorize('edit', $post);
でも大丈夫です。認可のロジックが同じ為です。

むしろ、'update'は辞めて、'edit'に統一した方が良いと思います。
十中八九、edit と update はロジックが同じになりますので。

それと、同箇所で、
$post->fill($params)->save();
$this->authorize('update', $post);
とありますが、save() した後に、authorize() を呼び出しても遅いので、順番は入れ替えないとまずいと思います。

で、問題の件ですが、正直良く分からないと言えば、良く分からないのですが、store メソッドでの
Post::create($params); で、'user_id' が渡ってないですよね?
post と user が紐付いて無くないですか?
user_id は、nullable でないので、なぜここでエラーにならないのでしょうか?
何か別の方法で紐付けているのでしょうか?

投稿2019/12/22 16:23

nshiro

総合スコア185

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

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

GO999

2019/12/23 14:29

nshiroさん、丁寧なご回答誠に有難う御座います。 当方初心者である為、書いてある意味の半分くらいしか理解できません。調べます。 $params = $request->validate([ 'title' => 'required|max:50', 'body' => 'required|max:2000', ]); から、$paramsに入っているのは'title'と'body'のみで、'user_id'が渡っていなく、「投稿者が誰か指定されていない状態で投稿されている」と言うことでしょうか。なので、編集しようとしても投稿者と投稿内容のIDを合致させられていないためunauthorizedと表示されると言うことでしょうか? なぜエラーにならないのかは分かりません。。 自分の中ではPostPolicy.phpで紐付けしている考えでした。勝手ですが、もし打開案があればご教授いただけると本当に助かります。
nshiro

2019/12/23 16:19

あくまで推測の1つですが、そうなります。 ただ、DBに登録されたデータを直接見る事はできませんか?phpMyAdmn などのツールを使って。 登録されているデータを直接見れば、user と post がちゃんと紐付いているかは、すぐに分かるかと思います。
GO999

2019/12/24 10:15

nshiroさん、お忙しいところ、ご回答誠に有難う御座います。 SQLiteManagerを使用すれば見られると複数のサイトにありまして、ダウンロードしましたがXamppでは無い為かうまく行かず。。もう少し勉強してみます。 Post::create($params); でuser_idを渡す良い方法はありますでしょうか?
nshiro

2019/12/24 11:32

SQLite 使っているのですね。 DBの中身を直接見られないと、開発も大変だと思いますので、何かしら利用した方が良いと思います。 Post::create($params); ↓ auth()->user()->posts()->create($params); で試されてみては如何でしょうか? それでもダメな場合、PostPolicy で edit メソッド内で、 return $user->id === $post->user_id; ↓ dump($user->id); dd($post->user_id); return $user->id === $post->user_id; としてみて、どのようなデータが渡っているのか、確認してみると良いかと思います。
GO999

2019/12/25 13:55

nshiroさん、毎回丁寧なご回答誠に有難う御座います ①まず Post::create($params); ↓ auth()->user()->posts()->create($params); に変えて投稿作成ボタンを押したところ↓ 「SQLSTATE[HY000]: General error: 1 table posts has no column named user_id (SQL: insert into "posts" ("title", "body", "user_id", "updated_at", "created_at") values (テスト, we, 46, 2019-12-25 13:32:20, 2019-12-25 13:32:20))」 とエラーが出ました。posts tableにuser_idが無い、と言うことでしょうか? ②次にPostPolicyを return $user->id === $post->user_id; ↓ dump($user->id); dd($post->user_id); return $user->id === $post->user_id; に変えて編集ボタンを押すと、1行目にユーザーのIDが表示され、2行目はNullと表示されます。 以上のことから分かることは、どう言うわけかPostsテーブルにuser_idが作成されていない状態であり、PostControllerのstoreメソッドでは受け渡すuser_idが存在しない為、正常に作動し、また全てのユーザーの編集を阻んでいる、ということでしょうか?Postsテーブルにはuser_idがファイル上は存在していると考えますが、何か別の方法があるのでしょうか? お忙しいところ恐れ入りますがよろしくお願い申し上げます。
nshiro

2019/12/25 14:24

database/migrations/posts_table.php には、$table->unsignedInteger('user_id'); と書かれているのに、 実際は、postsテーブルには、user_id が存在していないようですね。 後からマイグレーションファイルに追加したのでしょうか? 一旦全てのテーブルを削除して、再度テーブルを作り直すので良ければ、 php artisan migrate:fresh で再度、マイグレーションを行ってみてはいかがでしょうか。
GO999

2019/12/26 13:48

nshiroさん、毎回丁寧なご回答誠に有難う御座います。 はい、おっしゃる通り、後からuser_idを追加いたしました。 migrateしていなかったようです。。 ①php artisan migrate:freshを行いマイグレーションし直し、PostControllerのPost::create($params); を auth()->user()->posts()->create($params);に変更しました。 ②その後、PostPolicyのeditメソッド内で↓ dump($user->id); dd($post->user_id); return $user->id === $post->user_id; と入力し編集ボタンを押すと、1行目にユーザーのIDが 2 と表示され、2行目にはpostのuser_idが "2" と表示されます。(user_idにのみ"2"とダブルクォーテーションが付いているのが気になります。。) ③これで行けるかな、と思いdump($user->id); と dd($post->user_id);を外して、再度編集ボタンを押すと、This action is unauthorized.と出てしまいます。 うまくuser_idを渡せているようですが、ユーザーのIDと合致していると認可されていない状態と考えます。AuthServiceProviderとPostPolicyとPostControllerで、そこの処理はできていると思っていたのですが、どこか問題があるのでしょうか? すみませんがよろしくお願いします。
nshiro

2019/12/26 14:30

return $user->id === $post->user_id; だと型チェックまで行っているので、=== ではなく、== にすれば解決すると思います。 return $user->id == $post->user_id; $user->id の方は、int型に変換されているのに対し、$post->user_id の方は、文字列のままなのですね…。 (自分の案件で確認する限りは、共に int 型に変換されますが。何故かは分かりません…) 本来なら、より Laravel らしく return $user->is($post->user); みたいな書き方もできるのですが、型が一致していない状態だと、うまく行かないと思います。
GO999

2019/12/26 14:51 編集

できました!!!!! ①そもそもuser_idがデータベースに反映されていなかった。 ②PostPolicyでuser_idが渡っていなかった。 この2点が今回の主な問題点だと思います。 nshiroさん、ここ数日、僕の相談にお付き合いしていただき有難う御座います。 初めてのポートフォリオで自分ではどうしても解決できず諦めかけていたところ、親切に助けていただいて感謝いたします。 次は、管理者は全ての機能を使えるようにしようと思います。多分、またしくじるので、自分で調べてどうしようも無くなった際はまたよろしくお願いします。。
nshiro

2019/12/26 15:10

無事、解決して良かったです! Laravelは奥が深くてまだまだ私も学習中ですが、お互い頑張りましょう。
guest

0

AuthServiceProvider.phpで、Userや、UserPolicy、Post、PostPolicyを使うためにはそれらをあらかじめ呼び出す必要があります。

ということで最初に以下のコードを追加しましょう。
(参考にされたサイトでもよく見ると追加されてあります。)

PHP

1use App\Post; 2use App\Policies\PostPolicy; 3use App\User; 4use App\Policies\UserPolicy;

あとちなみにpostControllerでupdateのauthorizeが、
$this->authorize('edit', $post);
になってしまっています。多分これはあまり関係ないですが。

自分でもうちょっとデバッグするなら、一回PostPolicyのupdateとかのところで単純にtrueをreturnするようにしてみたり、$user->idをddで出してみたりしてみても良いのかもしれません。

投稿2019/12/21 16:45

aoies

総合スコア331

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

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

GO999

2019/12/22 03:29

aolesさん、丁寧なご回答とアドバイスを誠に有難うございます。 おっしゃられたようにAuthServiceProvider.phpに上記のコードを追加し、postControllerの間違いも修正致しましたが、依然として編集出来ない状態でございます。 お忙しいところ申し訳無いですが、もし他に考えうることが御座いましたら、何卒ご教示のほどよろしくお願いいたします。
aoies

2019/12/22 08:30

同様に、PostPolicyでも同様にPostオブジェクトを使っているため、 use App\Post; を書き加える必要があります。
GO999

2019/12/22 09:57

aolesさん、丁寧なご回答を誠に有難うございます。 PostPolicyにuse App\Post;を追加しましたが変化なく、UserPolicyにも同様に追加してみましたが変化ありませんでした。 何度もすみませんが、他に考えうることが御座いましたら、何卒ご教示のほどよろしくお願いいたします。
aoies

2019/12/22 11:31

これは関係ないかなと思うのですが、一応、ドキュメント通りなら"use App\Http\Controllers\Controller;"もPostControllerに追加しても良いかもしれません。 あとは、PostPolicyに public function edit(User $user, Post $post) { dd($user->id); return $user->id === $post->user_id; } とか書くと、policyまでちゃんと到達できてるかの確認とか、user->idがわたっているのかの確認とかができ、どこに問題があるかはっきりしてくるかと思います。($post->user_idも同様に) 私もそんなに詳しくないので確かなことが言えず申し訳ないのですが。
GO999

2019/12/22 12:30

aolesさん、丁寧なご回答を誠に有難うございます。 public function edit(User $user, Post $post) { dd($user->id); return $user->id === $post->user_id; } と書き換えてブラウザを更新するとエラーメッセージが出てしまいます。 これはデータが空っぽということでしょうか?
aoies

2019/12/22 20:40

ddを使った上でchromeの検証→network→赤字のやつ、を見るとあれば$user->idが見れます。 ddは、そこでデータ処理を停止して引数の変数の値を表示するメソッドです。それで$user->id、$post->user_idとしてどんな値がわたっているか確認できます。
GO999

2019/12/23 14:37

aolesさん、丁寧なご回答を誠に有難うございます。 デバックの方法を教えてくれて助かりました。 この方法を使用して打開策が無いかもっと検討してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問