I have a resource controller called StreamController.php
, that utilizes a policy called StreamPolicy.php
.
In my controller, I have this:
//StreamController.php
/**
* Construct method.
*/
public function __construct()
{
$this->middleware('auth');
$this->authorizeResource(Stream::class, 'stream');
}
With above, all the RESTful endpoints is successfully "protected" using the policy.
However, I have added a new method to my controller, called documents()
, like so:
//web.php
Route::get('streams/{stream}/documents', 'StreamController@documents');
//StreamController.php
/**
* Display the imported documents of the resource
*
* @return \Illuminate\Http\Response
*/
public function documents(Stream $stream)
{
return view('streams.documents', compact('stream'));
}
Now the problem is if I visit the URL:
example.com/streams/1 and I am not the owner of the stream, I get a 403 page - but if I go to: example.com/streams/1/documents and I am not the owner of the stream, I can still access the page.
What am I doing wrong? How can I make so my policy also covers the documents()
methods in my controller?
Edit:
This is my StreamPolicy.php
file:
//StreamPolicy.php
namespace App\Policies;
use App\User;
use App\Stream;
use Illuminate\Auth\Access\HandlesAuthorization;
class StreamPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view the stream.
*
* @param \App\User $user
* @param \App\Stream $stream
* @return mixed
*/
public function view(User $user, Stream $stream)
{
return $user->id == $stream->user_id;
}
/**
* Determine whether the user can create streams.
*
* @param \App\User $user
* @return mixed
*/
public function create(User $user)
{
//
return true;
}
/**
* Determine whether the user can update the stream.
*
* @param \App\User $user
* @param \App\Stream $stream
* @return mixed
*/
public function update(User $user, Stream $stream)
{
//
return $user->id == $stream->user_id;
}
/**
* Determine whether the user can delete the stream.
*
* @param \App\User $user
* @param \App\Stream $stream
* @return mixed
*/
public function delete(User $user, Stream $stream)
{
//
return $user->id == $stream->user_id;
}
/**
* Determine whether the user can restore the stream.
*
* @param \App\User $user
* @param \App\Stream $stream
* @return mixed
*/
public function restore(User $user, Stream $stream)
{
//
}
/**
* Determine whether the user can permanently delete the stream.
*
* @param \App\User $user
* @param \App\Stream $stream
* @return mixed
*/
public function forceDelete(User $user, Stream $stream)
{
//
}
}
Controller.php uses "AuthorizesRequest" trait which defines below 2 methods:
trait AuthorizesRequests
{
/**
* Get the map of resource methods to ability names.
*
* @return array
*/
protected function resourceAbilityMap()
{
return [
'show' => 'view',
'create' => 'create',
'store' => 'create',
'edit' => 'update',
'update' => 'update',
'destroy' => 'delete',
];
}
/**
* Get the list of resource methods which do not have model parameters.
*
* @return array
*/
protected function resourceMethodsWithoutModels()
{
return ['index', 'create', 'store'];
}
You can override these 2 protected methods per controller basis because every controller extends Controller.php
class UserController extends Controller
{
public function __construct ()
{
$this->authorizeResource ( User::class, 'user' );
}
/**
* Get the map of resource methods to ability names.
*
* @return array
*/
protected function resourceAbilityMap()
{
return [
'show' => 'view',
'create' => 'create',
'store' => 'create',
'edit' => 'update',
'update' => 'update',
'destroy' => 'delete',
'customMethod'=>'customMethod',
'customMethodWithoutModel'=>'customMethodWithoutModel'
];
}
/**
* Get the list of resource methods which do not have model parameters.
*
* @return array
*/
protected function resourceMethodsWithoutModels()
{
return ['index', 'create', 'store','customMethodWithoutModel'];
}
Its Policy Class
class UserPolicy
{
/**
* Determine whether the user can custom method.
*
* @param \App\User $user
* @param \App\User $model
* @return mixed
*/
public function customMethod(User $user, User $model){
return true;
}
/**
* Determine whether the user can custom method without model.
*
* @param \App\User $user
* @return mixed
*/
public function customMethodWithoutModel(User $user){
return true;
}
I don't know exactly why is not working but I'm afraid that the authorizeResource
method only handles the routes for the well-known resources end-points: view, create, update, delete and restore.
Later edit: Take a look in the docs to see which are the actions handled by the Resource Controllers https://laravel.com/docs/5.7/controllers#resource-controllers
What you should do is to explicitly set the authorization to the new route:
Route::get('streams/{stream}/documents', 'StreamController@documents')->middleware('can:documents,stream');
Of course, the documents
method should exist on the StreamPolicy
class.
OR
To authorize inside the StreamController.documents
method:
public function documents(Stream $stream)
{
$this->authorize('documents', $stream);
return view('streams.documents', compact('stream'));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With