Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

BogdanLaravel's avatar

Authorization

I would much appreciate help on this one. Every model in my app uses same policy. "DefaultPolicy", policies are binded to models only on Nova requests meaning that for api calls policies are not handled. In the default policy I have defined before method which will handle authorization.

class DefaultPolicy
{
    /**
     * Perform pre-authorization checks.
     */
    public function before(User $user, string $ability, string stdObject/model class): ?bool
    {
        $ability = $modelClass.':'.$ability;

        return Gate::any([$ability], $user->permissions);
    }
    \All of the methods bellow return false since it won't even get to them. I removed definitions because message is too long.
    public function viewAny(User $user)

    public function view(User $user, Model $model)

    public function create(User $user)

    public function update(User $user, Model $model)

    public function delete(User $user, Model $model)

    public function restore(User $user, Model $model)

    public function forceDelete(User $user, Model $model)
}

In this case, when authorization checks are for create or viewAny it works fine since in third parametar I get model class I'm authorizing upon. But when checks are for single model like view, update, delete, restore and forcedelete where it gets model. In third parametar I get stdClass which has properties of that model. Because of that I don't know which specific model it is. As you can see I'm utilizing permissions in format "modelClass:policyMethod".

Is there a way to override Laravel\Nova\Authorizable trait or to get the model class in policy before method?

0 likes
3 replies
alden8's avatar

@bogdanlaravel

-- inject Laravel\Nova\Resource via Constructor:

class DefaultPolicy
{
    protected $resource;

    public function __construct(Resource $resource)
    {
        $this->resource = $resource;
    }

    public function before(User $user, string $ability, $model)
    {
        $modelClass = $this->resource::newModel()->getMorphClass();
        // ... continue with authorization logic
    }
}

-- create a custom trait extending Authorizable:

trait CustomAuthorizable
{
    protected function callPolicyBefore(User $user, string $ability, $model = null)
    {
        $modelClass = $model ? get_class($model) : $this->resource::newModel()->getMorphClass();
        return call_user_func([$this->policy, 'before'], $user, $ability, $modelClass);
    }
}

-- create a middleware or use controller-level authorization:

public function update(Request $request, $modelId)
{
    $model = Model::findOrFail($modelId);

    if (!Gate::allows('update', $model)) {
        // ... return unauthorized response
    }

    // ... rest of the update logic
}
1 like
BogdanLaravel's avatar

@alden8

Thank you for the reply, I managed to do it another way.

I overriden authorizeTo and authorizedTo methods from Laravel\Nova\Authorizable trait in my resource abstract class. There I was able to pass model class in gate check and authorize calls

Gate::forUser(Nova::user($request))->check($ability, get_class(static::newModel())) Gate::forUser(Nova::user($request))->authorize($ability, get_class(static::newModel()));

1 like

Please or to participate in this conversation.