This post is from the professional Laravel developer community, original link: learnku.com/laravel/t/8…

Associate a user with a role

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

Once you have installed the extension pack you can do this:

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

// Add permissions by role.
$user->assignRole('writer');

// Add a permission to the role
$role->givePermissionTo('edit articles');
Copy the code

If you add multiple guards to a single user, extensions can handle this very well. Each guard assigned to the user has its own permissions and roles. Read the Using Multiple Guards section for more information.

Since all permissions will be registered with Laravel’s Gate, you can call Laravel’s default ‘can’ method to test whether the user has permissions:

$user->can('edit articles');
Copy the code

Spatie is a Web design agency based in Antwerp, Belgium. You can find all the open source projects on our website.

The installation

Laravel

This package can be used in Laravel 5.4 or later, if you are using an older version of Laravel, you can switch to the v1 branch of the package.

You can install this package using Composer:

composer require spatie/laravel-permission
Copy the code

In Laravel 5.5, service providers are automatically registered. In older versions of Laravel, you need to add them to config/app.php as follows:

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

You can issue migration with the following command:

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

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

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

After the migration is published, you can create a role and permission table by running the following command:

php artisan migrate
Copy the code

You can generate the configuration file by running the following command:

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

When the configuration file is published, you can see that 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,];Copy the code

Lumen

Install by Composer:

composer require spatie/laravel-permission
Copy the code

Copy required 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
Copy the code

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

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

Now, perform the migration:

php artisan migrate
Copy the code

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,
]);
Copy the code

Similarly, register configuration and service providers:

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

use

First, add Spatie\Permission\Traits\HasRoles Traits to the User model:

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

class User extends Authenticatable
{
    use HasRoles;

    // ...
}
Copy the code
  • Please note if you need in another model, for examplePageaddHasRolesTraits you need to addprotected $guard_name = 'web';Into this model, otherwise an error will be reported.
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

   // ...
}
Copy the code

This package allows users to associate with permissions and roles. Each role is associated with multiple permissions. Both Role and Permission are Eloquent models, and they are created using the name parameter, as follows:

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

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

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

$role->givePermissionTo($permission);
$permission->assignRole($role);
Copy the code

Multiple permissions can be synchronized to a role using one of the following methods:

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

You can remove permissions by role using one of the following methods:

$role->revokePermissionTo($permission);
$permission->removeRole($role);
Copy the code

If you use multiple guards, guard_name must be set, as mentioned in the using multiple Guards section.

The HasRoles trait has Eloquent model relationships that can be accessed directly through relationships or used as a basic query:

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

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

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

HasRoles trait also adds a role scope to your model that allows you to retrieve users for specific roles or privileges:

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

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

The trait also adds scope so that you can only get users with certain permissions.

$users = User::permission('edit articles')->get(); // Only users with 'edit articles' privileges (inherited or assigned directly) are returned.
Copy the code

The role scope takes a string, either a \Spatie\Permission\Models\Permission object or a \Illuminate\Support\Collection object.

Use “direct” permissions (see 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']);
Copy the code

Revoke a user’s permission:

$user->revokePermissionTo('edit articles');
Copy the code

To revoke or add a permission in a single operation:

$user->syncPermissions(['edit articles'.'delete articles']);
Copy the code

You can determine if a user has this permission:

$user->hasPermissionTo('edit articles');
Copy the code

Check whether the user has multiple permissions:

$user->hasAnyPermission(['edit articles'.'publish articles'.'unpublish articles']);
Copy the code

Once it’s saved, it registers with the default guard of the Illuminate\Auth\Access\Gate class. So you can use Laravel’s default CAN method to determine whether a user has a certain permission:

$user->can('edit articles');
Copy the code

Permission by role

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']);
Copy the code

Roles can be removed from a user:

$user->removeRole('writer');
Copy the code

Characters can also be synchronized:

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

You can determine if a user contains a role:

$user->hasRole('writer');
Copy the code

You can also determine if a user contains one of a given list of roles:

$user->hasAnyRole(Role::all());
Copy the code

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

$user->hasAllRoles(Role::all());
Copy the code

AssignRole, hasRole, hasAnyRole, hasAllRoles, and removeRole can accept a string, As a parameter, either a \Spatie\Permission\Models\Role object or a \Illuminate\Support\Collection object.

Permissions can be assigned to a role:

$role->givePermissionTo('edit articles');
Copy the code

You can determine if a role contains certain permissions:

$role->hasPermissionTo('edit articles');
Copy the code

Permissions can also be removed from a role:

$role->revokePermissionTo('edit articles');
Copy the code

The givePermissionTo and revokePermissionTo functions can take a string or a Spatie\Permission\Models\Permission object as an argument.

Permissions are automatically inherited from roles. In addition, individual rights can be assigned to users. Such as:

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

$user->assignRole('writer');

$user->givePermissionTo('delete articles');
Copy the code

In the example above, the role is given permission to edit the article, and the role is assigned to the user. Users can now edit and delete articles. The Delete permission is directly assigned to a user. It returns true when we call $user->hasDirectPermission(‘delete articles’), and false corresponds to $user->hasDirectPermission(‘ Edit articles’).

This approach is useful if you set permissions for roles and users in your application and want to limit or change the inherited permissions of user roles (only the direct permissions of the user are allowed to change).

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();
Copy the code

All responses are collections of Spatie\Permission\Models\Permission objects.

If we follow the previous example, the first response will be a collection with delete Article permissions, the second response will be a collection with Edit Article permissions, and the third response will contain the collection of both.

Using Blade syntax

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

You can do this by passing in the second parameter guard.

Blade grammatical Role

Testing a specific role:

@role('writer'(I'm a writer! @elseI'm not a writer... @endroleCopy the code

The equivalent of

@hasrole('writer'(I'm a writer! @elseI'm not a writer... @endhasroleCopy the code

Test any of the roles in the passed list:

@hasanyRole ($collectionOfRoles) I have one or more permissions here @elseI don't have any of these permissions @endHasanyRole// or
@hasanyrole('writer|admin') I am a writer or admin@elseI am neither writer nor admin@endhasanyroleCopy the code

Tests for all roles

I'm @ for hasallRoles ($collectionOfRoles)elseI'm not @endHasallRoles for any of these roles// or
@hasallroles('writer|admin') I am both writer and admin@elseI'm not a writer or admin@endHasallRolesCopy the code

Blade template with Permissions

This extension does not provide specific Blade directives for permissions, but instead uses the @CAN directive that comes with Laravel to verify user permissions. Here’s an example:

@can('edit articles')
  //
@endcan
Copy the code

Here’s another chestnut:

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

Using multiple Guards

When using the default Auth configuration of Laravel, all of the methods in the above examples work fine and no additional configuration is required. When there are multiple Guards, validating permissions and roles is a bit like a namespace. This means that each Guard has roles and permissions associated with its user model.

Access permissions and roles through multiple guards

Guard (config(‘auth.defaults.guard’)) is used by default for new permissions and roles. Guard_name = guard_name; guard_name = guard_name; guard_name = guard_name

// 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']);
Copy the code

Verify that the user has permission to specify guard:

$user->hasPermissionTo('publish articles'.'admin');
Copy the code

User authorization and role assignment

You can use the method above using Permissions via Roles to authorize and assign roles to users. Just make sure that the guard_name of the permission or role is the same as the guard of the user, otherwise a GuardDoesNotMatch exception will be thrown

Multiple Guards are used in blade directives

All blade DirectivesUsing Blade directives are the same for multiple Guards, just use Guard_name as the second parameter. Here’s an example:

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

Using middleware

This package contains two middleware components: 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,
];
Copy the code

You can use middleware to secure your routing:

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

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

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

In addition, you can use the | (pipe) character to distinguish multiple roles, or permissions:

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

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

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

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

Failed to capture roles and permissions

If you want to override the default 403 response, you can catch an UnauthorizedException via the application’s exception catching mechanism:

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

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

Copy the code

Use the artisan command

You can create roles and permissions from the console using the artisan command.

php artisan permission:create-role writer
Copy the code
php artisan permission:create-permission "edit articles"
Copy the code

When you create roles and permissions for a particular guard, you can use the guard name as the second argument:

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

Unit testing

In the test of your application, if you don’t have in the setUp () test method of filling the roles and permissions data as part of the test, you’re likely to encounter the problem of the chicken or the egg came first, the roles and permissions have not registered to door face (because you test after they are registered in front), the solution to this problem is simple: Just add the setUp() method to your test to re-register permissions as follows:

    public function setUp(a)
    {
        // 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();
    }
Copy the code

Database population

There are two things to note about database population

  1. It is best to update the following spatie.permission. Cache before populating data to avoid cache collision errors, which can be resolved with an Artisan command (see troubleshooting below: Or clear the cache directly in a Seeder class (see the example below).

  2. Here is an example of data populating that clears the cache, creates permissions, and then 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(a)
    	{
        	// Reset the cache for roles and permissions
            app()['cache']->forget('spatie.permission.cache');
    
            // Create permission
            Permission::create(['name'= >'edit articles']);
            Permission::create(['name'= >'delete articles']);
            Permission::create(['name'= >'publish articles']);
            Permission::create(['name'= >'unpublish articles']);
    
            // Create a role and grant the created permissions
            $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'); }}Copy the code

extension

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

  • yourRoleModels need to inherit
  • Spatie\Permission\Models\Rolemodel
  • yourPermissionModels need to inheritSpatie\Permission\Models\Permissionmodel

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

  • yourRoleThe model needs to be implemented
  • Spatie\Permission\Contracts\Role
  • yourPermissionYou need to implementSpatie\Permission\Contracts\Permission

In both cases, you need to specify your new model in the configuration, either for extension or replacement. To do this, you must update the models.role and models.Permission values in the configuration file after publishing the configuration. Run the following command:

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

The cache

Role and permission data is cached to speed performance.

The cache is automatically reset when you manipulate roles and permissions using the provided methods:

$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);
Copy the code

However, if you manipulate permissions and role data directly from the database instead of calling the methods we provide, your changes will not appear in the application unless you manually reset the cache.

Manually reset cache

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

php artisan cache:forget spatie.permission.cache
Copy the code

Cache identifier

Tip: If you are using a caching service such as Redis or memcached, or if you have other websites running on your server and you are likely to run into cache conflicts, it is advisable to set your own cache prefix. Set unique identifiers 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 does not have a user interface, you need to create your own. Please refer to this tutorial by Caleb Oki.

test

composer test
Copy the code

Update log

See the Update Log for more recent updates

Contribute code

See contribution code for details.

security

If you find any security-related issues, send an email to [email protected] instead of using the issue tracker.

postcards

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

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

We posted all the postcards we received on the company website.

thanks

  • Freek Van der Herten
  • All Contributors

This expansion pack is largely based on Jeffrey Way’s very cool Laracasts lessons on permissions and roles. This is his source address in this repo on GitHub.

Special thanks to Alex Vanderbist, who helped with the V2 release, and Chris Brown, who helped maintain the expansion pack for a long time.

resources

  • How do I create a user interface for managing permissions and roles

choose

Povilas Korop wrote an article in Laravel News that makes a comparison. He contrasts laravel-Permission with Joseph Silber’s Bouncer, which is also an excellent package in our book.

To support our

Spatie is a Web design agency based in Antwerp, Belgium. You can see an overview of our open source projects on our website.

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

The license

MIT License (MIT). See license File for more information.