Framework: Custom deny() method in policy is not called

Created on 19 Oct 2018  路  9Comments  路  Source: laravel/framework

  • Laravel Version: 5.5.44 (5.7 also shows this issue)
  • PHP Version: 7.2.4
  • Database Driver & Version:

Description:

If you override deny() in a policy and then authorize an ability that fails, it does not call the custom deny() method of the policy. This seems similar to #25260

Steps To Reproduce:

I have created a policy using php artisan make:policy JobPolicy. The policy that was generated uses the HandlesAuthorization trait which defines 2 methods allow() and deny(). I created a custom deny() method in my policy to send a custom error response. I am calling $this->authorize('update', $job) in a controller and I am not seeing the custom response returned from deny(). If you look in Illuminate\Auth\Access\Gate::authorize() it calls allow() or deny() depending on the result but it is the deny() method on the Gate, not the one from the policy. Note: Gate also uses the HandlesAuthorization trait.

<?php

namespace App\Policies;

use App\Models\Employer;
use App\Models\Job;
use Illuminate\Auth\Access\HandlesAuthorization;

class JobPolicy
{
    use HandlesAuthorization;

    protected function deny($message = 'This action is unauthorized.')
    {
        //return response()->json([
        //    'custom' => 'Custom message',
        //]);
       throw new \Exception('custom message');
    }

    public function update(Employer $employer, Job $job)
    {
        return false;
    }
}

In the controller you just need to do something like this:

    public function update(Request $request, Job $job)
    {
        $this->authorize('update', $job);
    }

Most helpful comment

The trait allows you to use the provided methods in the logic of your policy methods:

    public function edit(User $user, Model $model)
    {
        if (!$user->controls($model)) {
            $this->deny("You can't do this!");
        }
        return true;
    }

AFAIK this is the only intended function of the trait.
See #10231. where this was added.

All 9 comments

Please post the policy and controller code.

I think you can not send response from here. You need to throw custom exception same as laravel doing here.

I have updated the code to throw an exception with a custom message.

My main point I am trying to make is that the custom deny() in the policy is never called which seems like a bug. Why include the HandlesAuthorization trait in the policy if it is not called?

Have you registered policies rightly?

26208

Closing this since this PR addresses the issue #26208

The trait allows you to use the provided methods in the logic of your policy methods:

    public function edit(User $user, Model $model)
    {
        if (!$user->controls($model)) {
            $this->deny("You can't do this!");
        }
        return true;
    }

AFAIK this is the only intended function of the trait.
See #10231. where this was added.

Thank you so much for the example.
Is this documented?
I think no.

No. Ive always used it that way because I saw the pull request come through. Maybe @josephsilber could update the docs. If not, I'll try to make time to do it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shopblocks picture shopblocks  路  3Comments

iivanov2 picture iivanov2  路  3Comments

YannPl picture YannPl  路  3Comments

ghost picture ghost  路  3Comments

JamborJan picture JamborJan  路  3Comments