Skip to content

JosephSilber/bouncer

Repository files navigation

Bouncer

Build Status Total Downloads License

Bouncer is an elegant, framework-agnostic approach to managing roles and abilities for any app using Eloquent models.

Table of Contents

Click to expand

Introduction

Bouncer is an elegant, framework-agnostic approach to managing roles and abilities for any app using Eloquent models. With an expressive and fluent syntax, it stays out of your way as much as possible: use it when you want, ignore it when you don't.

For a quick, glanceable list of Bouncer's features, check outthe cheat sheet.

Bouncer works well with other abilities you have hard-coded in your own app. Your code always takes precedence: if your code allows an action, Bouncer will not interfere.

Once installed, you can simply tell the bouncer what you want to allow at the gate:

// Give a user the ability to create posts
Bouncer::allow($user)->to('create',Post::class);

// Alternatively, do it through a role
Bouncer::allow('admin')->to('create',Post::class);
Bouncer::assign('admin')->to($user);

// You can also grant an ability only to a specific model
Bouncer::allow($user)->to('edit',$post);

When you check abilities at Laravel's gate, Bouncer will automatically be consulted. If Bouncer sees an ability that has been granted to the current user (whether directly, or through a role) it'll authorize the check.

Installation

Note:Bouncer v1.0.2 requires PHP 8.2+ and Laravel/Eloquent 11+.

If you're on Laravel v6-v10, useBouncer v1.0.1.If you're on Laravel v5.5-v5.8, useBouncer RC6.

Installing Bouncer in a Laravel app

  1. Install Bouncer withcomposer:

    composer require silber/bouncer
    
  2. Add Bouncer's trait to your user model:

    useSilber\Bouncer\Database\HasRolesAndAbilities;
    
    classUserextendsModel
    {
    useHasRolesAndAbilities;
    }
  3. Now, to run Bouncer's migrations. First publish the migrations into your app'smigrationsdirectory, by running the following command:

    php artisan vendor:publish --tag= "bouncer.migrations"
    
  4. Finally, run the migrations:

    php artisan migrate
    

Facade

Whenever you use theBouncerfacade in your code, remember to add this line to your namespace imports at the top of the file:

useBouncer;

For more information about Laravel Facades, refer tothe Laravel documentation.

Installing Bouncer in a non-Laravel app

  1. Install Bouncer withcomposer:

    composer require silber/bouncer
    
  2. Set up the database withthe Eloquent Capsule component:

    useIlluminate\Database\Capsule\ManagerasCapsule;
    
    $capsule=newCapsule;
    
    $capsule->addConnection([/* connection config */]);
    
    $capsule->setAsGlobal();

    Refer tothe Eloquent Capsule documentationfor more details.

  3. Run the migrations by either of the following methods:

  4. Add Bouncer's trait to your user model:

    useIlluminate\Database\Eloquent\Model;
    useSilber\Bouncer\Database\HasRolesAndAbilities;
    
    classUserextendsModel
    {
    useHasRolesAndAbilities;
    }
  5. Create an instance of Bouncer:

    useSilber\Bouncer\Bouncer;
    
    $bouncer=Bouncer::create();
    
    // If you are in a request with a current user
    // that you'd wish to check permissions for,
    // pass that user to the "create" method:
    $bouncer=Bouncer::create($user);

    If you're using dependency injection in your app, you may register theBouncerinstance as a singleton in the container:

    useSilber\Bouncer\Bouncer;
    useIlluminate\Container\Container;
    
    Container::getInstance()->singleton(Bouncer::class,function() {
    returnBouncer::create();
    });

    You can now injectBouncerinto any class that needs it.

    Thecreatemethod creates aBouncerinstance with sensible defaults. To fully customize it, use themakemethod to get a factory instance. Callcreate()on the factory to create theBouncerinstance:

    useSilber\Bouncer\Bouncer;
    
    $bouncer=Bouncer::make()
    ->withCache($customCacheInstance)
    ->create();

    Check outtheFactoryclassto see all the customizations available.

  6. Set which model is used as the user model throughout your app:

    $bouncer->useUserModel(User::class);

    For additional configuration, check outthe Configuration sectionbelow.

Enabling cache

By default, Bouncer's queries are cached for the current request. For better performance, you may want toenable cross-request caching.

Usage

Adding roles and abilities to users is made extremely easy. You do not have to create a role or an ability in advance. Simply pass the name of the role/ability, and Bouncer will create it if it doesn't exist.

Note:the examples below all use theBouncerfacade. If you don't use facades, you can instead inject an instance ofSilber\Bouncer\Bouncerinto your class.

Creating roles and abilities

Let's create a role calledadminand give it the ability toban-usersfrom our site:

Bouncer::allow('admin')->to('ban-users');

That's it. Behind the scenes, Bouncer will create both aRolemodel and anAbilitymodel for you.

If you want to add additional attributes to the role/ability, such as a human-readable title, you can manually create them using theroleandabilitymethods on theBouncerclass:

$admin=Bouncer::role()->firstOrCreate([
'name'=>'admin',
'title'=>'Administrator',
]);

$ban=Bouncer::ability()->firstOrCreate([
'name'=>'ban-users',
'title'=>'Ban users',
]);

Bouncer::allow($admin)->to($ban);

Assigning roles to a user

To now give theadminrole to a user, simply tell the bouncer that the given user should be assigned the admin role:

Bouncer::assign('admin')->to($user);

Alternatively, you can call theassignmethod directly on the user:

$user->assign('admin');

Giving a user an ability directly

Sometimes you might want to give a user an ability directly, without using a role:

Bouncer::allow($user)->to('ban-users');

Here too you can accomplish the same directly off of the user:

$user->allow('ban-users');

Restricting an ability to a model

Sometimes you might want to restrict an ability to a specific model type. Simply pass the model name as a second argument:

Bouncer::allow($user)->to('edit',Post::class);

If you want to restrict the ability to a specific model instance, pass in the actual model instead:

Bouncer::allow($user)->to('edit',$post);

Allowing a user or role to "own" a model

Use thetoOwnmethod to allow users to managetheir ownmodels:

Bouncer::allow($user)->toOwn(Post::class);

Now, when checking at the gate whether the user may perform an action on a given post, the post'suser_idwill be compared to the logged-in user'sid(this can be customized). If they match, the gate will allow the action.

The above will grant all abilities on a user's "owned" models. You can restrict the abilities by following it up with a call to thetomethod:

Bouncer::allow($user)->toOwn(Post::class)->to('view');

// Or pass it an array of abilities:
Bouncer::allow($user)->toOwn(Post::class)->to(['view','update']);

You can also allow users to own alltypesof models in your application:

Bouncer::allow($user)->toOwnEverything();

// And to restrict ownership to a given ability
Bouncer::allow($user)->toOwnEverything()->to('view');

Retracting a role from a user

The bouncer can also retract a previously-assigned role from a user:

Bouncer::retract('admin')->from($user);

Or do it directly on the user:

$user->retract('admin');

Removing an ability

The bouncer can also remove an ability previously granted to a user:

Bouncer::disallow($user)->to('ban-users');

Or directly on the user:

$user->disallow('ban-users');

Note:if the user has a role that allows them toban-users,they will still have that ability. To disallow it, either remove the ability from the role or retract the role from the user.

If the ability has been granted through a role, tell the bouncer to remove the ability from the role instead:

Bouncer::disallow('admin')->to('ban-users');

To remove an ability for a specific model type, pass in its name as a second argument:

Bouncer::disallow($user)->to('delete',Post::class);

Warning:if the user has an ability todeletea specific$postinstance, the code above willnotremove that ability. You will have to remove the ability separately - by passing in the actual$postas a second argument - as shown below.

To remove an ability for a specific model instance, pass in the actual model instead:

Bouncer::disallow($user)->to('delete',$post);

Note:thedisallowmethod only removes abilities that were previously given to this user/role. If you want to disallow a subset of what a more-general ability has allowed, usetheforbidmethod.

Forbidding an ability

Bouncer also allows you toforbida given ability, for more fine-grained control. At times you may wish to grant a user/role an ability that covers a wide range of actions, but then restrict a small subset of those actions.

Here are some examples:

  • You might allow a user to generally view all documents, but have a specific highly-classified document that they should not be allowed to view:

    Bouncer::allow($user)->to('view',Document::class);
    
    Bouncer::forbid($user)->to('view',$classifiedDocument);
  • You may wish to allow yoursuperadmins to do everything in your app, including adding/removing users. Then you may have anadminrole that can do everythingbesidesmanaging users:

    Bouncer::allow('superadmin')->everything();
    
    Bouncer::allow('admin')->everything();
    Bouncer::forbid('admin')->toManage(User::class);
  • You may wish to occasionally ban users, removing their permission to all abilities. However, actually removing all of their roles & abilities would mean that when the ban is removed we'll have to figure out what their original roles and abilities were.

    Using a forbidden ability means that they can keep all their existing roles and abilities, but still not be authorized for anything. We can accomplish this by creating a specialbannedrole, for which we'll forbid everything:

    Bouncer::forbid('banned')->everything();

    Then, whenever we want to ban a user, we'll assign them thebannedrole:

    Bouncer::assign('banned')->to($user);

    To remove the ban, we'll simply retract the role from the user:

    Bouncer::retract('banned')->from($user);

As you can see, Bouncer's forbidden abilities gives you a lot of granular control over the permissions in your app.

Unforbidding an ability

To remove a forbidden ability, use theunforbidmethod:

Bouncer::unforbid($user)->to('view',$classifiedDocument);

Note:this will remove any previously-forbidden ability. It willnotauthomatically allow the ability if it's not already allowed by a different regular ability granted to this user/role.

Checking a user's roles

Note:Generally speaking, you should not have a need to check roles directly. It is better to allow a role certain abilities, then check for those abilities instead. If what you need is very general, you can create very broad abilities. For example, anaccess-dashboardability is always better than checking foradminoreditorroles directly. For the rare occasion that you do want to check a role, that functionality is available here.

The bouncer can check if a user has a specific role:

Bouncer::is($user)->a('moderator');

If the role you're checking starts with a vowel, you might want to use theanalias method:

Bouncer::is($user)->an('admin');

For the inverse, you can also check if a userdoesn'thave a specific role:

Bouncer::is($user)->notA('moderator');

Bouncer::is($user)->notAn('admin');

You can check if a user has one of many roles:

Bouncer::is($user)->a('moderator','editor');

You can also check if the user has all of the given roles:

Bouncer::is($user)->all('editor','moderator');

You can also check if a user has none of the given roles:

Bouncer::is($user)->notAn('editor','moderator');

These checks can also be done directly on the user:

$user->isAn('admin');
$user->isA('subscriber');

$user->isNotAn('admin');
$user->isNotA('subscriber');

$user->isAll('editor','moderator');

Querying users by their roles

You can query your users by whether they have a given role:

$users=User::whereIs('admin')->get();

You may also pass in multiple roles, to query for users that haveanyof the given roles:

$users=User::whereIs('superadmin','admin')->get();

To query for users who haveallof the given roles, use thewhereIsAllmethod:

$users=User::whereIsAll('sales','marketing')->get();

Getting all roles for a user

You can get all roles for a user directly from the user model:

$roles=$user->getRoles();

Getting all abilities for a user

You can get all abilities for a user directly from the user model:

$abilities=$user->getAbilities();

This will return a collection of the user's allowed abilities, including any abilities granted to the user through their roles.

You can also get a list of abilities that have beenexplicitlyforfidden:

$forbiddenAbilities=$user->getForbiddenAbilities();

Authorizing users

Authorizing users is handled directly atLaravel'sGate,or on the user model ($user->can($ability)).

For convenience, theBouncerclass provides these passthrough methods:

Bouncer::can($ability);
Bouncer::can($ability,$model);

Bouncer::canAny($abilities);
Bouncer::canAny($abilities,$model);

Bouncer::cannot($ability);
Bouncer::cannot($ability,$model);

Bouncer::authorize($ability);
Bouncer::authorize($ability,$model);

These call directly into their equivalent methods on theGateclass.

Blade directives

Bouncer does not add its own blade directives. Since Bouncer works directly with Laravel's gate, simply use its@candirective to check for the current user's abilities:

@can ('update', $post)
<ahref= "{{ route('post.update', $post) }}">Edit Post</a>
@endcan

Since checking for roles directly is generallynot recommended,Bouncer does not ship with a separate directive for that. If you still insist on checking for roles, you can do so using the general@ifdirective:

@if($user->isAn('admin'))
//
@endif

Refreshing the cache

All queries executed by Bouncer are cached for the current request. If you enablecross-request caching,the cache will persist across different requests.

Whenever you need, you can fully refresh the bouncer's cache:

Bouncer::refresh();

Note:fully refreshing the cache for all users usescache tagsif they're available. Not all cache drivers support this. Refer toLaravel's documentationto see if your driver supports cache tags. If your driver does not support cache tags, callingrefreshmight be a little slow, depending on the amount of users in your system.

Alternatively, you can refresh the cache only for a specific user:

Bouncer::refreshFor($user);

Note:When usingmulti-tenancy scopes,this will only refresh the cache for the user in the current scope's context. To clear cached data for the same user in a different scope context, it must be called from within that scope.

Multi-tenancy

Bouncer fully supports multi-tenant apps, allowing you to seamlessly integrate Bouncer's roles and abilities for all tenants within the same app.

The scope middleware

To get started, first publishthe scope middlewareinto your app:

php artisan vendor:publish --tag= "bouncer.middleware"

The middleware will now be published toapp/Http/Middleware/ScopeBouncer.php.This middleware is where you tell Bouncer which tenant to use for the current request. For example, assuming your users all have anaccount_idattribute, this is what your middleware would look like:

publicfunctionhandle($request,Closure$next)
{
$tenantId=$request->user()->account_id;

Bouncer::scope()->to($tenantId);

return$next($request);
}

You are of course free to modify this middleware to fit your app's needs, such as pulling the tenant information from a subdomain et al.

Now with the middleware in place, be sure to register it in yourHTTP Kernel:

protected$middlewareGroups= [
'web'=> [
// Keep the existing middleware here, and add this:
\App\Http\Middleware\ScopeBouncer::class,
]
];

All of Bouncer's queries will now be scoped to the given tenant.

Customizing Bouncer's scope

Depending on your app's setup, you may not actually wantallof the queries to be scoped to the current tenant. For example, you may have a fixed set of roles/abilities that are the same for all tenants, and only allow your users to control which users are assigned which roles, and which roles have which abilities. To achieve this, you can tell Bouncer's scope to only scope the relationships between Bouncer's models, but not the models themselves:

Bouncer::scope()->to($tenantId)->onlyRelations();

Furthermore, your app might not even allow its users to control which abilities a given role has. In that case, tell Bouncer's scope to exclude role abilities from the scope, so that those relationships stay global across all tenants:

Bouncer::scope()->to($tenantId)->onlyRelations()->dontScopeRoleAbilities();

If your needs are even more specialized than what's outlined above, you can create your ownScopewith whatever custom logic you need:

useSilber\Bouncer\Contracts\Scope;

classMyScopeimplementsScope
{
// Whatever custom logic your app needs
}

Then, in a service provider, register your custom scope:

Bouncer::scope(newMyScope);

Bouncer will call the methods on theScopeinterface at various points in its execution. You are free to handle them according to your specific needs.

Configuration

Bouncer ships with sensible defaults, so most of the time there should be no need for any configuration. For finer-grained control, Bouncer can be customized by calling various configuration methods on theBouncerclass.

If you only use one or two of these config options, you can stick them into yourmainAppServiceProvider'sbootmethod.If they start growing, you may create a separateBouncerServiceProviderclass inyourapp/Providersdirectory(remember to register it intheprovidersconfig array).

Cache

By default, all queries executed by Bouncer are cached for the current request. For better performance, you may want to use cross-request caching:

Bouncer::cache();

Warning:if you enable cross-request caching, you are responsible to refresh the cache whenever you make changes to user's roles/abilities. For how to refresh the cache, readrefreshing the cache.

On the contrary, you may at times wish tocompletely disablethe cache, even within the same request:

Bouncer::dontCache();

This is particularly useful in unit tests, when you want to run assertions against roles/abilities that have just been granted.

Tables

To change the database table names used by Bouncer, pass an associative array to thetablesmethod. The keys should be Bouncer's default table names, and the values should be the table names you wish to use. You do not have to pass in all tables names; only the ones you wish to change.

Bouncer::tables([
'abilities'=>'my_abilities',
'permissions'=>'granted_abilities',
]);

Bouncer's published migration uses the table names from this configuration, so be sure to have these in place before actually running the migration.

Custom models

You can easily extend Bouncer's built-inRoleandAbilitymodels:

namespaceApp\Models;

useSilber\Bouncer\Database\AbilityasBouncerAbility;

classAbilityextendsBouncerAbility
{
// custom code
}
namespaceApp\Models;

useSilber\Bouncer\Database\RoleasBouncerRole;

classRoleextendsBouncerRole
{
// custom code
}

Alternatively, you can use Bouncer'sIsAbilityandIsRoletraits without actually extending any of Bouncer's models:

namespaceApp\Models;

useIlluminate\Database\Eloquent\Model;
useSilber\Bouncer\Database\Concerns\IsAbility;

classAbilityextendsModel
{
useIsAbility;

// custom code
}
namespaceApp\Models;

useIlluminate\Database\Eloquent\Model;
useSilber\Bouncer\Database\Concerns\IsRole;

classRoleextendsModel
{
useIsRole;

// custom code
}

If you use the traits instead of extending Bouncer's models, be sure to set the proper$tablename and$fillablefields yourself.

Regardless of which method you use, the next step is to actually tell Bouncer to use your custom models:

Bouncer::useAbilityModel(\App\Models\Ability::class);
Bouncer::useRoleModel(\App\Models\Role::class);

Note:Eloquent determines the foreign key of relationships based on the parent model name (seethe Eloquent docs). To keep things simple, name your custom classes the same as Bouncer's:AbilityandRole,respectively.

If you need to use different names, be sure to either update your migration file or override the relationship methods to explicitly set their foreign keys.

User Model

By default, Bouncer automaticallyuses the user model of the default auth guard.

If you're using Bouncer with a non-default guard, and it uses a different user model, you should let Bouncer know about the user model you want to use:

Bouncer::useUserModel(\App\Admin::class);

Ownership

In Bouncer, the concept of ownership is used toallow users to perform actions on models they "own".

By default, Bouncer will check the model'suser_idagainst the current user's primary key. If needed, this can be set to a different attribute:

Bouncer::ownedVia('userId');

If different models use different columns for ownership, you can register them separately:

Bouncer::ownedVia(Post::class,'created_by');
Bouncer::ownedVia(Order::class,'entered_by');

For greater control, you can pass a closure with your custom logic:

Bouncer::ownedVia(Game::class,function($game,$user) {
return$game->team_id==$user->team_id;
});

FAQ

There are some concepts in Bouncer that people keep on asking about, so here's a short list of some of those topics:

Where do I set up my app's roles and abilities?

Seeding the initial roles and abilities can be done in a regularLaravel seederclass. Start by creating a specific seeder file for Bouncer:

php artisan make:seeder BouncerSeeder

Place all of your seeding roles & abilities code inthe seeder'srunmethod.Here's an example of what that might look like:

useBouncer;
useIlluminate\Database\Seeder;

classBouncerSeederextendsSeeder
{
publicfunctionrun()
{
Bouncer::allow('superadmin')->everything();

Bouncer::allow('admin')->everything();
Bouncer::forbid('admin')->toManage(User::class);

Bouncer::allow('editor')->to('create',Post::class);
Bouncer::allow('editor')->toOwn(Post::class);

// etc.
}
}

To actually run it, pass the seeder's class name to theclassoption of thedb:seedcommand:

php artisan db:seed --class=BouncerSeeder

Can I use a different set of roles & abilities for the public & dashboard sections of my site, respectively?

Bouncer'sscopecan be used to section off different parts of the site, creating a silo for each one of them with its own set of roles & abilities:

  1. Create aScopeBouncermiddlewarethat takes an$identifierand sets it as the current scope:

    useBouncer,Closure;
    
    classScopeBouncer
    {
    publicfunctionhandle($request,Closure$next,$identifier)
    {
    Bouncer::scope()->to($identifier);
    
    return$next($request);
    }
    }
  2. Register this new middleware as a route middleware in yourHTTP Kernel class:

    protected$routeMiddleware= [
    // Keep the other route middleware, and add this:
    'scope-bouncer'=> \App\Http\Middleware\ScopeBouncer::class,
    ];
  3. In yourroute service provider,apply this middleware with a different identifier for the public routes and the dashboard routes, respectively:

    Route::middleware(['web','scope-bouncer:1'])
    ->namespace($this->namespace)
    ->group(base_path('routes/public.php'));
    
    Route::middleware(['web','scope-bouncer:2'])
    ->namespace($this->namespace)
    ->group(base_path('routes/dashboard.php'));

That's it. All roles and abilities will now be separately scoped for each section of your site. To fine-tune the extent of the scope, seeCustomizing Bouncer's scope.

I'm trying to run the migration, but I'm getting a SQL error that the "specified key was too long"

Starting with Laravel 5.4, the default database character set is nowutf8mb4.If you're using older versions of some databases (MySQL below 5.7.7, or MariaDB below 10.2.2) with Laravel 5.4+, you'll get a SQL error when trying to create an index on a string column. To fix this, change Laravel's default string length in yourAppServiceProvider:

useIlluminate\Support\Facades\Schema;

publicfunctionboot()
{
Schema::defaultStringLength(191);
}

You can read more inthis Laravel News article.

I'm trying to run the migration, but I'm getting a SQL error that there is a "Syntax error or access violation: 1064... to use near json not null)"

JSON columns are a relatively new addition to MySQL (5.7.8) and MariaDB (10.2.7). If you're using an older version of these databases, you cannot use JSON columns.

The best solution would be to upgrade your DB. If that's not currently possible, you can changeyour published migration fileto use atextcolumn instead:

-$table->json('options')->nullable();
+$table->text('options')->nullable();

Console commands

bouncer:clean

Thebouncer:cleancommand deletes unused abilities. Running this command will delete 2 types of unused abilities:

  • Unassigned abilities- abilities that are not assigned to anyone. For example:

    Bouncer::allow($user)->to('view',Plan::class);
    
    Bouncer::disallow($user)->to('view',Plan::class);

    At this point, the "view plans" ability is not assigned to anyone, so it'll get deleted.

    Note:depending on the context of your app, you may not want to delete these. If you let your users manage abilities in your app's UI, you probablydon'twant to delete unassigned abilities. See below.

  • Orphaned abilities- model abilities whose models have been deleted:

    Bouncer::allow($user)->to('delete',$plan);
    
    $plan->delete();

    Since the plan no longer exists, the ability is no longer of any use, so it'll get deleted.

If you only want to delete one type of unused ability, run it with one of the following flags:

php artisan bouncer:clean --unassigned
php artisan bouncer:clean --orphaned

If you don't pass it any flags, it will delete both types of unused abilities.

To automatically run this command periodically, add it toyour console kernel's schedule:

$schedule->command('bouncer:clean')->weekly();

Cheat Sheet

// Adding abilities for users
Bouncer::allow($user)->to('ban-users');
Bouncer::allow($user)->to('edit',Post::class);
Bouncer::allow($user)->to('delete',$post);

Bouncer::allow($user)->everything();
Bouncer::allow($user)->toManage(Post::class);
Bouncer::allow($user)->toManage($post);
Bouncer::allow($user)->to('view')->everything();

Bouncer::allow($user)->toOwn(Post::class);
Bouncer::allow($user)->toOwnEverything();

// Removing abilities uses the same syntax, e.g.
Bouncer::disallow($user)->to('delete',$post);
Bouncer::disallow($user)->toManage(Post::class);
Bouncer::disallow($user)->toOwn(Post::class);

// Adding & removing abilities for roles
Bouncer::allow('admin')->to('ban-users');
Bouncer::disallow('admin')->to('ban-users');

// You can also forbid specific abilities with the same syntax...
Bouncer::forbid($user)->to('delete',$post);

// And also remove a forbidden ability with the same syntax...
Bouncer::unforbid($user)->to('delete',$post);

// Re-syncing a user's abilities
Bouncer::sync($user)->abilities($abilities);

// Assigning & retracting roles from users
Bouncer::assign('admin')->to($user);
Bouncer::retract('admin')->from($user);

// Assigning roles to multiple users by ID
Bouncer::assign('admin')->to([1,2,3]);

// Re-syncing a user's roles
Bouncer::sync($user)->roles($roles);

// Checking the current user's abilities
$boolean=Bouncer::can('ban-users');
$boolean=Bouncer::can('edit',Post::class);
$boolean=Bouncer::can('delete',$post);

$boolean=Bouncer::cannot('ban-users');
$boolean=Bouncer::cannot('edit',Post::class);
$boolean=Bouncer::cannot('delete',$post);

// Checking a user's roles
$boolean=Bouncer::is($user)->a('subscriber');
$boolean=Bouncer::is($user)->an('admin');
$boolean=Bouncer::is($user)->notA('subscriber');
$boolean=Bouncer::is($user)->notAn('admin');
$boolean=Bouncer::is($user)->a('moderator','editor');
$boolean=Bouncer::is($user)->all('moderator','editor');

Bouncer::cache();
Bouncer::dontCache();

Bouncer::refresh();
Bouncer::refreshFor($user);

Some of this functionality is also available directly on the user model:

$user->allow('ban-users');
$user->allow('edit',Post::class);
$user->allow('delete',$post);

$user->disallow('ban-users');
$user->disallow('edit',Post::class);
$user->disallow('delete',$post);

$user->assign('admin');
$user->retract('admin');

$boolean=$user->isAn('admin');
$boolean=$user->isAn('editor','moderator');
$boolean=$user->isAll('moderator','editor');
$boolean=$user->isNotAn('admin','moderator');

// Querying users by their roles
$users=User::whereIs('superadmin')->get();
$users=User::whereIs('superadmin','admin')->get();
$users=User::whereIsAll('sales','marketing')->get();

$abilities=$user->getAbilities();
$forbidden=$user->getForbiddenAbilities();

Alternative

Among the bajillion packages thatSpatiehas so graciously bestowed upon the community, you'll find the excellentlaravel-permissionpackage. Like Bouncer, it nicely integrates with Laravel's built-in gate and permission checks, but has a different set of design choices when it comes to syntax, DB structure & features.

License

Bouncer is open-sourced software licensed under theMIT license