-
Notifications
You must be signed in to change notification settings - Fork 31
authorizeResource() and nested resources support #1612
Comments
+1 I've had the exact same problem today when writing a simple API. Also in order to fix the authorization part, I've had to add an explicit model binding into
I find this quite dirty and I'm sure there is a better way to fix. But at least, comments MUST BELONG to a valid Axel EDIT 1: thinking about it afterwards, the best way to solve this is in my opinion to globally change the implicit model binding method when using nested resources. The |
@royduin Using your example, I'd create a route group for your post related sub-resources and apply the You could then just use |
I came up with a workaround that allows you to use IMHO, the docs should contain an example of how to handle this scenario (similar to my example below) or the implementation of My nested context is a little different than the Posts -> Comments relationship but I'll rewrite everything to use the previously mentioned example as it may be more relatable. First, for this to work, the nested resource that you need must exist within the URL. Route::resource('/post/{post}/comment', 'CommentController'); In your CommentController.php, you need a class CommentController extends Controller
{
public function __construct()
{
$this->authorizeResource(Comment::class);
}
// .... your other resource methods ...
} In your CommentPolicy.php, you need a class UserPolicy
{
use HandlesAuthorization;
public function __construct(Request $request)
{
$this->post = $request->route('post');
}
// ... your other policy methods ...
} Then in your individual policy checks, you should be able to access public function create(User $user)
{
dd($this->post); // dumps the post model resolved from the route!
}
// A more functional example ...
public function delete(User $user, Comment $comment)
{
// Maybe comment creators can delete their comments...
// Or the post owner can delete any comment associated with their post...
return $user->id == $comment->user_id ||
(
$user->id == $this->post->user_id &&
$comment->post_id == $this->post->id
);
} If this is documented somewhere, I couldn't find it... At a minimum, I think it would be very helpful to have a similar example listed in the docs under Authorization. |
Just like with
However this doesn't work for resource methods without a model (index, create, store) as Laravel will use the model name instead of the parameter. See line 90 in
I was able to fix this by switching out this line with this bit of code:
But this is just my quick fix, maybe someone can make a nice PR out of it? |
While I agree modifications could be made to Laravel - it is possible to do this using the <?php
namespace App\Http\Controllers\Post;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreComment;
use App\Http\Requests\UpdateComment;
use App\Http\Resources\Polymorphic\CommentResource;
use App\Models\Polymorphic\Comment;
use App\Models\Post\Post;
class PostCommentsController extends Controller
{
public function __construct()
{
$this->middleware('can:view,post')->only(['index', 'store']);
$this->middleware('can:create,' . Comment::class)->only('store');
$this->middleware('can:update,comment')->only('update');
$this->middleware('can:destroy,comment')->only('destroy');
}
public function index(Post $post)
{
return CommentResource::collection($post->comments);
}
public function store(Post $post, StoreComment $request)
{
return $post->comments()->create(array_merge($request->validated(), [
'user_id' => auth()->id()
]));
}
public function update(Comment $comment, UpdateComment $request)
{
$comment->update($request->validated());
}
public function destroy(Comment $comment)
{
$comment->delete();
}
} |
Let's say we have nested resource "clients" of a business :
If we want to use build in authorizeResource() we can do this :
Don't forget to type hint business in client controller :
and in ClientPolicy
Best Regards to all |
When we've a post with comments we can use:
In our
PostController
, with aPostPolicy
and the reference in theAuthServiceProvider
. But; when we can't useauthorizeResource()
in theCommentController
when we've nested them:And we need access to the post and the comment in the
CommentPolicy
. For example:This is currently only possible by specifying the authorization in every controller method, for example:
With this example you can say; sure but you can access the post from the comment right? Just use
$comment->post
in the policy and you're done. But what about the create method in the policy? For example; a user may only create a comment when the post is published:To accomplish this we've to use:
It would be cleaner to have the possibility to use
authorizeResource()
with nested resources so we don't have to specify authorization in every restful controller method.The text was updated successfully, but these errors were encountered: