Michael
Michael

Reputation: 576

Laravel 5.6 Authorizing actions using policies

I am trying to implement a policy to block the edit functionality of a resource.

My route:

Route::resource('imagerequests', 'ImageRequestController');

My ImageRequestPolicy

class ImageRequestPolicy
{
    use HandlesAuthorization;

    const STATUS_EXECUTING = "executing";

    public function edit(ImageRequest $imageRequest)
    {
        return $imageRequest->status !== self::STATUS_EXECUTING;
    }
}

But I can still access the ´imagerequests/{id}/edit´ route

EDIT

/**
 * The policy mappings for the application.
 *
 * @var array
 */
protected $policies = [
    ImageRequest::class => ImageRequestPolicy::class,
];

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    //
}

ImageRequest Model

class ImageRequest extends Model

Edit ImageRequestController method

public function edit($id, ImageRequest $imageRequest)
{
    $this->authorize('edit', $imageRequest);

    $imageRequest = ImageRequest::findOrFail($id);
    $requestTypes = RequestType::all();
    $attachments = $this->imageRequestRepository->getAttachmentsListOfImageRequestById($id);

    return view('imagerequest.edit', compact('imageRequest', 'requestTypes', 'attachments'));
}

Upvotes: 3

Views: 1333

Answers (3)

Namoshek
Namoshek

Reputation: 6544

There is a difference between gates and policies that is somewhat hard to grasp from the documentation. Gates are used to authorize controller methods while resources are responsible to authorize actions regarding models, i.e. actual database records.

So in your case, you should be using gates and not policies. You can still use your existing policy class, but you have to register it differently. Instead of using

/**
 * The policy mappings for the application.
 *
 * @var array
 */
protected $policies = [
    ImageRequest::class => ImageRequestPolicy::class,
];

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();
}

you should be using

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    Gate::resource('imageRequests', App\Policies\ImageRequestPolicy::class);
}

For further reference, have a look at the documentation on gates.

Upvotes: 0

Arthur Samarcos
Arthur Samarcos

Reputation: 3299

Your edit method is wrong, it's first argument must be the user:

public function edit(User $user, ImageRequest $imageRequest)
{
    return $imageRequest->status !== self::STATUS_EXECUTING;
}

Add to your ImageRequestController, edit method:

public function edit(ImageRequest $imageRequest) {

$this->authorize('edit',$imageRequest);

...

}

The $user argument is automaticaly added by laravel.

Also you need to register the policy in AuthServiceProvider.

protected $policies = [
    ImageRequest::class => ImageRequestPolicy::class,
];

And ImageRequest must extend Model class. Is it a model or a illuminate\http\request ?

There's something wrong with your controller. You sair your route is:

/imagerequests/26/edit

In your controller you are injecting a new, blank ImageRequest, maybe that's why it's passing the authorize test. Try this:

public function edit($id, ImageRequest $imageRequest)
{
    $imageRequest = ImageRequest::findOrFail($id);

    $this->authorize('edit', $imageRequest);

    $requestTypes = RequestType::all();
    $attachments = $this->imageRequestRepository->getAttachmentsListOfImageRequestById($id);

    return view('imagerequest.edit', compact('imageRequest', 'requestTypes', 'attachments'));
}

Upvotes: 4

Giulio Bambini
Giulio Bambini

Reputation: 4755

use middleware for protecting routes.

use App\Post;
Route::put('/post/{post}', function (Post $post) {
    // The current user may update the post...
})->middleware('can:update,post');

Hope this will help.

Upvotes: 0

Related Questions