kazak71/nova-permissions

Laravel Nova 4 Grouped Permissions

dev-master / 1.0.x-dev 2024-03-14 09:33 UTC

This package is auto-updated.

Last update: 2024-12-14 11:20:44 UTC


README

A Laravel Nova Tool that allows you to group your Permissions and attach it to Users. It uses Spatie's laravel-permission.

We have a Migration, Seed, Policy and Resource ready for a good Authorization Experience.

  1. Installation
  2. Permissions with Groups
  3. Customization
  4. Credits

Installation

You can install the package in to a Laravel app that uses Nova via composer:

composer require sereny/nova-permissions

Publish the Migration with the following command:

php artisan vendor:publish --provider="Sereny\NovaPermissions\ToolServiceProvider" --tag="migrations"

Migrate the Database:

php artisan migrate

Next up, you must register the tool with Nova. This is typically done in the tools method of the NovaServiceProvider.

// in app/Providers/NovaServiceProvider.php

// ...

public function tools()
{
    return [
        // ...
        new \Sereny\NovaPermissions\NovaPermissions(),
    ];
}

If you want to hide the tool from certain users, you can write your custom logic for the ability to see the tool:

// in app/Providers/NovaServiceProvider.php

// ...

public function tools()
{
    return [
        // ...
        (new \Sereny\NovaPermissions\NovaPermissions())->canSee(function ($request) {
            return $request->user()->isSuperAdmin();
        }),
    ];
}

Finally, add MorphToMany fields to you app/Nova/User resource:

// ...
use Laravel\Nova\Fields\MorphToMany;

public function fields(Request $request)
{
    return [
        // ...
        MorphToMany::make('Roles', 'roles', \Sereny\NovaPermissions\Nova\Role::class),
        MorphToMany::make('Permissions', 'permissions', \Sereny\NovaPermissions\Nova\Permission::class),
    ];
}

Add the Spatie\Permission\Traits\HasRoles trait to your User model(s):

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;

    // ...
}

A new menu item called Roles & Permissions will appear in your Nova app after installing this package.

Permissions with Groups

Index View

image

Detail View

image

Edit View

image

Database Seeding

Publish our Seeder with the following command:

php artisan vendor:publish --provider="Sereny\NovaPermissions\ToolServiceProvider" --tag="seeders"

This is just an example on how you could seed your Database with Roles and Permissions. Modify RolesAndPermissionsSeeder.php in database/seeders. List all your Models you want to have Permissions for in the $collection Array and change the email for the Super-Admin:

<?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class RolesAndPermissionsSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        // Reset cached roles and permissions
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

        $collection = collect([
            'Invoice',
            'Client',
            'Contact',
            'Payment',
            'Team',
            'User',
            'Role',
            'Permission'
            // ... your own models/permission you want to crate
        ]);

        $collection->each(function ($item, $key) {
            // create permissions for each collection item
            Permission::create(['group' => $item, 'name' => 'viewAny' . $item]);
            Permission::create(['group' => $item, 'name' => 'view' . $item]);
            Permission::create(['group' => $item, 'name' => 'update' . $item]);
            Permission::create(['group' => $item, 'name' => 'create' . $item]);
            Permission::create(['group' => $item, 'name' => 'delete' . $item]);
            Permission::create(['group' => $item, 'name' => 'destroy' . $item]);
        });

        // Create a Super-Admin Role and assign all permissions to it
        $role = Role::create(['name' => 'super-admin']);
        $role->givePermissionTo(Permission::all());

        // Give User Super-Admin Role
        $user = App\User::whereEmail('your@email.com')->first(); // enter your email here
        $user->assignRole('super-admin');
    }
}

Now you can seed the Database. Add $this->call(RolesAndPermissionsSeeder::class); to the DatabaseSeeder.

Note: If this doesn't work, run composer dumpautoload to autoload the Seeder.

Create a Model Policy

You can extend Sereny\NovaPermissions\Policies\BasePolicy and have a very clean Model Policy that works with Nova.

For Example: Create a new Contact Policy with php artisan make:policy ContactPolicy with the following code:

<?php

namespace App\Policies;

use Sereny\NovaPermissions\Policies\BasePolicy;

class ContactPolicy extends BasePolicy
{
    /**
     * The Permission key the Policy corresponds to.
     *
     * @var string
     */
    public $key = 'contact';
}

It should now work as exptected. Just create a Role, modify its Permissions and the Policy should take care of the rest.

Note: Don't forget to add your Policy to your $policies in App\Providers\AuthServiceProvider.

Note: Only extend the Policy if you have created your Permissions according to our Seeding Example. Otherwise, make sure to have viewAnyContact, viewContact, createContact, updateContact, deleteContact, restoreContact, destroyContact as Permissions in your Table in order to extend our Policy.

Super Admin

A Super Admin can do everything. If you extend our Policy, make sure to add a isSuperAdmin() Function to your App\User Model:

<?php

namespace App;

class User {

    /**
     * Determines if the User is a Super admin
     * @return null
    */
    public function isSuperAdmin()
    {
        return $this->hasRole('super-admin');
    }
}

Customizations

// in app/Providers/NovaServiceProvider.php

use App\Nova\Permission;
use App\Nova\Role;

// ...

public function tools()
{
    return [
        // ...
        \Sereny\NovaPermissions\NovaPermissions::make()
            ->roleResource(Role::class)
            ->permissionResource(Permission::class)
            ->disablePermissions()
            ->disableMenu();
            ->hideFieldsFromRole([
                'id',
                'guard_name'
            ])
            ->hideFieldsFromPermission([
                'id',
                'guard_name',
                'users',
                'roles'
            ])
            ->resolveGuardsUsing(function($request) {
                return [ 'web' ];
            })
            ->resolveModelForGuardUsing(function($request) {
                /** @var App\Auth\CustomGuard $guard */
                $guard = auth()->guard();
                return $guard->getProvider()->getModel();
            })
    ];
}

Important

To customize the Role model you need to use Sereny\NovaPermissions\Traits\SupportsRole trait:

// Role using UUID primary key

namespace App\Models;

use Illuminate\Support\Str;
use Sereny\NovaPermissions\Traits\SupportsRole;
use Spatie\Permission\Models\Role as BaseRole;

class Role extends BaseRole
{
    use SupportsRole; // REQUIRED TRAIT

     /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted(): void
    {
        static::saving(function (Role $role) {
            if ($role->id === null) {
                $role->id = Str::uuid()->toString();
            }
        });
    }

    /**
     * Force key type as string
     *
     * @return string
     */
    public function getKeyType()
    {
        return 'string';
    }

    /**
     * Disable incrementing
     *
     * @return bool
     */
    public function getIncrementing()
    {
        return false;
    }
}

Credits

This Package is inspired by eminiarts/nova-permissions.

A huge thanks goes to Spatie spatie/laravel-permission for their amazing work!