Role and permission control in spatie/Laravel-permission Laravel applications

The article was forwarded from the professional Laravel developer community with the original link: https://learnku.com/laravel/t...

Associate users with roles

This package allows you to manage user privileges and roles in the database.

When you install the extension pack, you can do this:

// Add a privilege to the user
$user->givePermissionTo('edit articles');

// Add permissions through roles.
$user->assignRole('writer');

// Add a privilege to a role
$role->givePermissionTo('edit articles');

If you add multiple guards to a single user, the expansion pack can also handle this very well. Each guard assigned to a user has its own privileges and roles. Read using multiple guards You can see more information in the chapter.

Because all permissions will be registered in Laravel's gate So you can call Laravel's default'can'method to test user permissions:

$user->can('edit articles');

Spatie is a web design organization based in Antwerp, Belgium.You can do it in our Official Web Find all open source projects.

install

Laravel

This package can be used in Laravel 5.4 or later. If you are using an older version of Lavel, you can switch to The v1 branch of this package To use.

You can install this package through composer:

composer require spatie/laravel-permission

Service providers are automatically registered in Laravel 5.5, and you need to add them to config/app.php as follows in older versions of Lavel:

'providers' => [
    // ...
    Spatie\Permission\PermissionServiceProvider::class,
];

You can publish using the following commands migration :

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"

If you use UUIDs or GUIDs in the User model, you can modify create_permission_tables.php migration and replace $table->morphs ('model'):

$table->uuid('model_id');
$table->string('model_type');

After migration is published, you can create roles and privilege tables by running the following commands:

php artisan migrate

You can run the following command to generate a configuration file:

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"

When the profile is published, you can see config/permission.php Includes:

return [

    'models' => [

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * Eloquent model should be used to retrieve your permissions. Of course, it
         * is often just the "Permission" model but you may use whatever you like.
         *
         * The model you want to use as a Permission model needs to implement the
         * `Spatie\Permission\Contracts\Permission` contract.
         */

        'permission' => Spatie\Permission\Models\Permission::class,

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * Eloquent model should be used to retrieve your roles. Of course, it
         * is often just the "Role" model but you may use whatever you like.
         *
         * The model you want to use as a Role model needs to implement the
         * `Spatie\Permission\Contracts\Role` contract.
         */

        'role' => Spatie\Permission\Models\Role::class,

    ],

    'table_names' => [

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your roles. We have chosen a basic
         * default value but you may easily change it to any table you like.
         */

        'roles' => 'roles',

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your permissions. We have chosen a basic
         * default value but you may easily change it to any table you like.
         */

        'permissions' => 'permissions',

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your models permissions. We have chosen a
         * basic default value but you may easily change it to any table you like.
         */

        'model_has_permissions' => 'model_has_permissions',

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your models roles. We have chosen a
         * basic default value but you may easily change it to any table you like.
         */

        'model_has_roles' => 'model_has_roles',

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your roles permissions. We have chosen a
         * basic default value but you may easily change it to any table you like.
         */

        'role_has_permissions' => 'role_has_permissions',
    ],

    /*
     * By default all permissions will be cached for 24 hours unless a permission or
     * role is updated. Then the cache will be flushed immediately.
     */

    'cache_expiration_time' => 60 * 24,
    
    /*
     * When set to true, the required permission/role names are added to the exception
     * message. This could be considered an information leak in some contexts, so
     * the default setting is false here for optimum safety.
     */

    'display_permission_in_exception' => false,
];

Lumen

Install through Composer:

composer require spatie/laravel-permission

Copy the necessary files:

cp vendor/spatie/laravel-permission/config/permission.php config/permission.php
cp vendor/spatie/laravel-permission/database/migrations/create_permission_tables.php.stub database/migrations/2018_01_01_000000_create_permission_tables.php

Another configuration file, config/auth.php, can be obtained from the Laravel repository or directly by executing the following command:

curl -Ls https://raw.githubusercontent.com/laravel/lumen-framework/5.5/config/auth.php -o config/auth.php

Now, perform the migration:

php artisan migrate

Next, in bootstrap/app.php, register the middleware:

$app->routeMiddleware([
    'auth'       => App\Http\Middleware\Authenticate::class,
    'permission' => Spatie\Permission\Middlewares\PermissionMiddleware::class,
    'role'       => Spatie\Permission\Middlewares\RoleMiddleware::class,
]);

Similarly, register configuration and service providers:

$app->configure('permission');
$app->register(Spatie\Permission\PermissionServiceProvider::class);

Use

First, add Spatie\Permission\TraitsHasRoles trait to the User model:

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

class User extends Authenticatable
{
    use HasRoles;

    // ...
}

  • Note that if you need to add HasRoles trait to another model, such as Page, you also need to add protected $guard_name ='web'; otherwise, you will get an error in this model.
use Illuminate\Database\Eloquent\Model;
use Spatie\Permission\Traits\HasRoles;

class Page extends Model
{
   use HasRoles;

   protected $guard_name = 'web'; // or whatever guard you want to use

   // ...
}

This package allows users to be associated with privileges and roles.Each role is associated with multiple privileges.
Both Role and Permission are Eloquent models, and they are created by passing in the parameter name, as follows:

use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

$role = Role::create(['name' => 'writer']);
$permission = Permission::create(['name' => 'edit articles']);

You can assign permissions to roles using one of the following methods:

$role->givePermissionTo($permission);
$permission->assignRole($role);

You can synchronize multiple privileges to a role using one of the following methods:

$role->syncPermissions($permissions);
$permission->syncRoles($roles);

Permissions can be removed through roles using one of the following methods:

$role->revokePermissionTo($permission);
$permission->removeRole($role);

If you are using multiple guards, guard_name must be set at Use multiple guards It is mentioned in the paragraph.

HasRoles trait has an Eloquent model relationship capability that can be accessed directly through a relationship or used as a basic query:

// Get all the permissions directly assigned to the user
$permissions = $user->permissions;

// Returns the privileges inherited by all users by granting roles
$permissions = $user->getAllPermissions();

// Get a collection of all defined roles
$roles = $user->getRoleNames(); // Return a collection

HasRoles trait also adds a role scope to your model to allow you to retrieve users for a specific role or privilege:

$users = User::role('writer')->get(); // Return users whose role is'writer'

role scope receives a string, \Spatie\Permission\Models\Role object or Illuminate\Support\Collection object.

This trait also adds a scope so that you can only get users with certain privileges.

$users = User::permission('edit articles')->get(); // Return only users with'edit articles'privileges (inherited from roles or directly assigned)

role scope receives a string, \Spatie\Permission\Models\Permission object or \Illuminate\Support\Collection object.

Use "direct" permissions (refer to roles and permissions below)

Assign permissions to any user:

$user->givePermissionTo('edit articles');

// You can also give multiple permission at once
$user->givePermissionTo('edit articles', 'delete articles');

// You may also pass an array
$user->givePermissionTo(['edit articles', 'delete articles']);

Revoke one of the user's privileges:

$user->revokePermissionTo('edit articles');

Revoke or add permissions in one operation:

$user->syncPermissions(['edit articles', 'delete articles']);

You can determine if a user has this privilege:

$user->hasPermissionTo('edit articles');

Determine if a user has multiple privileges:

$user->hasAnyPermission(['edit articles', 'publish articles', 'unpublish articles']);

Once the permissions are saved, it will be registered with the default guard of the Illuminate\AuthAccess\Gate class.So you can use Laravel's default can method to determine if a user has a certain privilege:

$user->can('edit articles');

Use permissions through roles

Roles can be assigned to any user:

$user->assignRole('writer');

// You can also assign multiple roles at once
$user->assignRole('writer', 'admin');
// or as an array
$user->assignRole(['writer', 'admin']);

Roles can be removed from a user:

$user->removeRole('writer');

Roles can also be synchronized:

// All current roles will be removed from the user and replaced by the array given
$user->syncRoles(['writer', 'admin']);

You can determine if a user has a role:

$user->hasRole('writer');

You can also determine if a user has one in the list of given roles:

$user->hasAnyRole(Role::all());

You can also determine if a user has all the given roles:

$user->hasAllRoles(Role::all());

The assignRole, hasRole, hasAnyRole, hasAllRoles, and removeRole functions can accept a string, a \Spatie\Permission\Models\Role object or a \Illuminate\Support\Collection object as a parameter.

Permissions can be assigned to a role:

$role->givePermissionTo('edit articles');

You can determine whether a role contains a privilege:

$role->hasPermissionTo('edit articles');

Permissions can also be removed from a role:

$role->revokePermissionTo('edit articles');

The givePermissionTo and revokePermissionTo functions can accept a string or a Spatie\Permission\ModelsPermission object as parameters.

Permissions are automatically inherited from roles.
In addition, personal rights can be assigned to users.
For example:

$role = Role::findByName('writer');
$role->givePermissionTo('edit articles');

$user->assignRole('writer');

$user->givePermissionTo('delete articles');

In the example above, the role is given permission to edit articles, and the role is assigned to the user.
Now users can edit and delete articles.The Delete permission is a direct permission assigned directly to the user.
When we call $user->hasDirectPermission ('delete articles'), it returns true.
false corresponds to $user->hasDirectPermission ('edit articles').

This can be useful if you set permissions for roles and users in your application and want to restrict or change the inherited permissions of user roles (allowing only the direct permissions of users to be changed).

You can list these permissions:

// Direct permissions
$user->getDirectPermissions() // Or $user->permissions;

// Permissions inherited from the user's roles
$user->getPermissionsViaRoles();

// All permissions which apply on the user (inherited and direct)
$user->getAllPermissions();

All responses are a collection of Spatie\Permission\ModelsPermission objects.

If we follow the previous example, the first response will be a collection with delete article privileges, the second response will be a collection with edit article privileges, and the third response will contain a collection of both.

Use Blade syntax

The package also adds Blade syntax to verify that the currently logged in user has all or a given role.

You can retrieve it by passing in the second parameter guard.

Blade Grammar Role

Test a specific role:

@role('writer')
    I'm a writer!
@else
   I'm not a writer...
@endrole

Amount to

@hasrole('writer')
    I'm a writer!
@else
   I'm not a writer...
@endhasrole

Test any role in the incoming list:

@hasanyrole($collectionOfRoles)
    I have one or more permissions here
@else
    I don't have any of these permissions
@endhasanyrole
// or
@hasanyrole('writer|admin')
    I am a writer or admin
@else
    I am neither a writer nor an admin
@endhasanyrole

Test for all roles

@hasallroles($collectionOfRoles)
    I am all of these characters
@else
    Neither of these characters are I
@endhasallroles
// or
@hasallroles('writer|admin')
    I am both a writer and admin
@else
    I am neither a writer nor an admin
@endhasallroles

Blade Templates and Permissions Permissions

This extension does not provide special Blade directives related to privileges, but uses Laravel's @can directive s to verify user privileges.Lift a chestnut:

@can('edit articles')
  //
@endcan

Raise another chestnut:

@if(auth()->user()->can('edit articles') && $some_other_condition)
  //
@endif

Use multiple guards

With Laravel's default auth configuration, all the methods in the above example work without additional configuration.
When there are multiple guards, checking permissions and roles is a bit like a namespace.This means that each guard has roles and privileges associated with its user model.

Use privileges and roles through multiple guards

The new permissions and roles default to the system default guard (config('auth.defaults.guard').When adding permissions and roles, you can specify guard through the guard_name attribute of the model:

// Create a superadmin role for the admin users
$role = Role::create(['guard_name' => 'admin', 'name' => 'superadmin']);

// Define a `publish articles` permission for the admin users belonging to the admin guard
$permission = Permission::create(['guard_name' => 'admin', 'name' => 'publish articles']);

// Define a *different* `publish articles` permission for the regular users belonging to the web guard
$permission = Permission::create(['guard_name' => 'web', 'name' => 'publish articles']);

Verify that the user has permission to specify guard:

$user->hasPermissionTo('publish articles', 'admin');

User authorization and role assignment

You can use the methods described above using permissions via roles Authorize and assign roles to users.You only need to ensure that the guard_name of the privilege or role is the same as the guard of the user, or you will throw a GuardDoesNotMatch exception

Use multiple guards in blade directives

All blade directives using blade directives This applies to multiple guards as well, simply using guard_name as the second parameter.Lift a chestnut:

@role('super-admin', 'admin')
    I am a super-admin!
@else
    I am not a super-admin...
@endrole

Using Middleware

This package contains two middleware, RoleMiddleware and PermissionMiddleware.You can add them to the app/Http/Kernel.php file.

protected $routeMiddleware = [
    // ...
    'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
    'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
];

You can use middleware to protect your routes:

Route::group(['middleware' => ['role:super-admin']], function () {
    //
});

Route::group(['middleware' => ['permission:publish articles']], function () {
    //
});

Route::group(['middleware' => ['role:super-admin','permission:publish articles']], function () {
    //
});

Alternatively, you can distinguish between roles or privileges by the | (pipe) character:

Route::group(['middleware' => ['role:super-admin|writer']], function () {
    //
});

Route::group(['middleware' => ['permission:publish articles|edit articles']], function () {
    //
});

Similarly, you can protect your controller by setting the required Middleware in the constructor:

public function __construct()
{
    $this->middleware(['role:super-admin','permission:publish articles|edit articles']);
}

Capturing roles and permissions failed

If you want to override the default 403 response, you can catch the UnauthorizedException exception by applying an exception capture mechanism:

public function render($request, Exception $exception)
{
    if ($exception instanceof \Spatie\Permission\Exceptions\UnauthorizedException) {
        // Code here ...
    }

    return parent::render($request, $exception);
}

Use artisan command

You can use the artisan command from the console to create roles and privileges.

php artisan permission:create-role writer
php artisan permission:create-permission "edit articles"

When you create roles and privileges for a particular guard, you can use the guard's name as the second parameter:

php artisan permission:create-role writer web
php artisan permission:create-permission "edit articles" web

unit testing

In the tests you apply, if you do not fill in the data for roles and privileges in the setUp() test method as part of the test, you will most likely encounter a chicken or egg problem, where roles and privileges have not been registered on the front of the door (because you tested that they were registered on the front of the door) to solve this problemIt's simple: just add the setUp() method to your tests to re-register permissions as follows:

    public function setUp()
    {
        // First call the setUp() method of the following parent class as normal
        parent::setUp();

        // Now re-register roles and permissions
        $this->app->make(\Spatie\Permission\PermissionRegistrar::class)->registerPermissions();
    }

Database Population

There are two points to note about database padding

  1. It is best to update the following spatie.permission.cache before populating the data to avoid cache conflict errors, which can be resolved with an Artisan command (refer to later troubleshooting: the cache section) or by clearing the cache directly in a seeder class (see the example below).
  2. Here is an example of data filling, which clears the cache, creates permissions, and assigns permissions to roles:

    use Illuminate\Database\Seeder;
    use Spatie\Permission\Models\Role;
    use Spatie\Permission\Models\Permission;
    
    class RolesAndPermissionsSeeder extends Seeder
    {
        public function run()
        {
            // Reset the cache of roles and privileges
            app()['cache']->forget('spatie.permission.cache');
    
            // create a privilege
            Permission::create(['name' => 'edit articles']);
            Permission::create(['name' => 'delete articles']);
            Permission::create(['name' => 'publish articles']);
            Permission::create(['name' => 'unpublish articles']);
    
            // Create roles and grant created privileges
            $role = Role::create(['name' => 'writer']);
            $role->givePermissionTo('edit articles');
            $role->givePermissionTo('delete articles');
    
            $role = Role::create(['name' => 'admin']);
            $role->givePermissionTo('publish articles');
            $role->givePermissionTo('unpublish articles');
        }
    }
    

extend

If you want to extend an existing Role or Permission model, note:

  • Your Role model needs to be inherited
  • Spatie\Permission\Models\Role Model
  • Your Permission model needs to inherit the Spatie\Permission\Models\Permission model

If you need to replace an existing Role or Permission model, remember:

  • Your Role model needs to be implemented
  • Spatie\Permission\Contracts\Role
  • Your Permission needs to implement Spatie\PermissionContracts\Permission

In both cases, whether extended or replaced, you need to specify your new model in the configuration.To do this, you must update the models.role and models.permission values in the configuration file after you publish the configuration.With the following command:

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"

cache

Role and privilege data is stored in the cache to speed up performance.

When you use the methods provided to manipulate roles and privileges, the cache is automatically reset:

$user->assignRole('writer');
$user->removeRole('writer');
$user->syncRoles(params);
$role->givePermissionTo('edit articles');
$role->revokePermissionTo('edit articles');
$role->syncPermissions(params);
$permission->assignRole('writer');
$permission->removeRole('writer');
$permission->syncRoles(params);

However, if you manipulate privileges, role data directly from the database instead of invoking the methods we provide, your changes will not occur to the application unless you manually reset the cache.

Manual Reset Cache

To manually reset the cache for this extension package, run the command:

php artisan cache:forget spatie.permission.cache

Cache Identifier

Suggestion: If you are using caching services such as redis or memcached, or if there are other websites running on your server, you may encounter cache conflicts, so setting your own cache prefix is far-reaching.
Set a unique identifier for each application in the / config / cache.php file.This will prevent other applications from accidentally using or changing your cached data.

Need a user interface?

This Extension Pack has no user interface and you need to create it yourself.Please refer to Caleb Oki Of This tutorial.

test

composer test

Update Log

see also Update Log To learn more about the latest updates

Contribution Code

See for details Contribution Code.

security

If you find any security related issues, please send an email to freek@spatie.be Instead of using the problem tracker.

Postcard

You can use this extension pack for free, but if you use it in a production environment, we'll appreciate sending us a postcard telling us which expansion pack you're using.

Our address is Spatie, Samberstraat 69D, 2060 Antwerp, Belgium.

We posted all the postcards we received to Company website.

Acknowledgement

This extension package is largely based on Jeffrey Way Very cool Laracasts
about Permissions and Roles Lessons for.This is his source address in this repo on GitHub.

Special thanks Alex Vanderbist , he's been very helpful with v2, and Chris Brown And he's been helping us maintain this extension package for a long time.

Resources

Choice

Povilas Korop Written articles An article in Laravel News A comparison is made in.He uses laravel-permission and Joseph Silber Of Bouncer ) By contrast, it is also a good package in our books.

Support us

Spatie is a web design organization in Antwerp, Belgium.You can see an overview of our open source projects On our website.

Does your business depend on our contributions?stay Patreon Help us.The money will be used to maintain old products and develop new ones.

Permit

MIT License. For more information, see License file .

Tags: PHP Laravel Database curl

Posted on Fri, 06 Sep 2019 19:02:41 -0700 by krabople