Search code examples
laravelrolespolicies

Laravel policy not running on update/delete model


I'm trying to make this policy stuff work, and i have followed the documentation. But it doesn't seem like the policy code is not even run.

I have Role model. And i created RolePolicy. The thing i want to do in the policy is to ensure that the role with the ID of 1 never-ever gets updated or deleted.

My RolePolicy looks like this:

<?php

namespace App\Policies;

use App\Models\Role;
use Illuminate\Support\Facades\Response;

class RolePolicy
{
    /**
     * Determine whether the user can update the model.
     *
     * @param  \App\User  $user
     * @param  \App\Models\Role  $role
     * @return mixed
     */
    public function update(Role $role)
    {
        return $role->id === 1
        ? Response::deny('Cannot change super-admin role')
        : Response::allow();
    }

    /**
     * Determine whether the user can delete the model.
     *
     * @param  \App\User  $user
     * @param  \App\Models\Role  $role
     * @return mixed
     */
    public function delete(Role $role)
    {
        return $role->id === 1
        ? Response::deny('Cannot delete super-admin role')
        : Response::allow();
    }
}

I even tried to do a dd() inside both delete and update method in the policy, but when i try to delete/update the model with the ID of 1, nothing happens. The dd wont run, nor will the response in the current code above.

I have registered the policy in the AuthServiceProvider where i also have this gate to give the super-admin all the permissions.

<?php

namespace App\Providers;

use App\Models\Role;
use App\Policies\RolePolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        Role::class => RolePolicy::class
    ];

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

        // Implicitly grant "Super Admin" role all permissions
        // This works in the app by using gate-related functions like auth()->user->can() and @can()
        Gate::before(function($user, $ability) {
            return $user->hasRole('super-admin') ? true : null;
        });
    }
}

Here is also my RoleController method for updating the Role model:

/**
 * Edit role
 *
 * @param Edit $request
 * @param Role $role
 * @return void
 */
public function postEdit(Edit $request, Role $role)
{
    # Validation checks happens in the FormRequest
    # Session flash also happens in FormRequest

    # Update model
    $role->update([
        'name' => $request->name
    ]);

    # Sync permissions
    $permissions = Permission::whereIn('name', $request->input('permissions', []))->get();
    $role->syncPermissions($permissions);

    return redirect(route('dashboard.roles.edit.get', ['role' => $role->id]))->with('success', 'Changes saved');
}

Does the gate i use to give all permissions have anything to do with the policy not running? Or what am i doing wrong here?

Thanks in advance if anyone can point me in the right direction.


Solution

  • The Gate::before method in the AuthServiceProvider was the problem. Removed this and rewrote the permissions, policies and some gates to get the error messages from the policies.

    Decided to give the role super-admin the permission * and check for this with $user->can() and middleware .....->middlware('can:*') and everything is working now.