[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-8489":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":35,"readmeContent":36,"aiSummary":37,"trendingCount":16,"starSnapshotCount":16,"syncStatus":38,"lastSyncTime":39,"discoverSource":40},8489,"bouncer","JosephSilber\u002Fbouncer","JosephSilber","Laravel Eloquent roles and abilities.","",null,"PHP",3576,335,84,45,0,1,6,29.58,"MIT License",false,"master",true,[25,26,27,28,29,30,31,32,33,34],"acl","auth","authorization","eloquent","laravel","multitenancy","permissions","php","roles","security","2026-06-12 02:01:54","\u003Cimg src=\"https:\u002F\u002Fuser-images.githubusercontent.com\u002F1403741\u002F39606419-587dbb1e-4f03-11e8-8e54-1bb2f39fb0f5.jpg\">\n\n# Bouncer\n\n\u003Cp>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Factions\">\u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Factions\u002Fworkflows\u002Ftests.yml\u002Fbadge.svg\" alt=\"Build Status\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fsilber\u002Fbouncer\">\u003Cimg src=\"https:\u002F\u002Fposer.pugx.org\u002Fsilber\u002Fbouncer\u002Fd\u002Ftotal.svg\" alt=\"Total Downloads\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Fblob\u002Fmaster\u002FLICENSE.txt\">\u003Cimg src=\"https:\u002F\u002Fposer.pugx.org\u002Fsilber\u002Fbouncer\u002Flicense.svg\" alt=\"License\">\u003C\u002Fa>\n\u003C\u002Fp>\n\nBouncer is an elegant, framework-agnostic approach to managing roles and abilities for any app using Eloquent models.\n\n## Table of Contents\n\n\u003Cdetails>\u003Csummary>Click to expand\u003C\u002Fsummary>\u003Cp>\n\n- [Introduction](#introduction)\n- [Installation](#installation)\n  - [Installing Bouncer in a Laravel app](#installing-bouncer-in-a-laravel-app)\n  - [Installing Bouncer in a non-Laravel app](#installing-bouncer-in-a-non-laravel-app)\n  - [Enabling cache](#enabling-cache)\n- [Usage](#usage)\n  - [Creating roles and abilities](#creating-roles-and-abilities)\n  - [Assigning roles to a user](#assigning-roles-to-a-user)\n  - [Giving a user an ability directly](#giving-a-user-an-ability-directly)\n  - [Restricting an ability to a model](#restricting-an-ability-to-a-model)\n  - [Allowing a user or role to \"own\" a model](#allowing-a-user-or-role-to-own-a-model)\n  - [Retracting a role from a user](#retracting-a-role-from-a-user)\n  - [Removing an ability](#removing-an-ability)\n  - [Forbidding an ability](#forbidding-an-ability)\n  - [Unforbidding an ability](#unforbidding-an-ability)\n  - [Checking a user's roles](#checking-a-users-roles)\n  - [Querying users by their roles](#querying-users-by-their-roles)\n  - [Getting all roles for a user](#getting-all-roles-for-a-user)\n  - [Getting all abilities for a user](#getting-all-abilities-for-a-user)\n  - [Authorizing users](#authorizing-users)\n  - [Blade directives](#blade-directives)\n  - [Refreshing the cache](#refreshing-the-cache)\n- [Multi-tenancy](#multi-tenancy)\n  - [The scope middleware](#the-scope-middleware)\n  - [Customizing Bouncer's scope](#customizing-bouncers-scope)\n- [Configuration](#configuration)\n  - [Cache](#cache)\n  - [Tables](#tables)\n  - [Custom models](#custom-models)\n  - [User Model](#user-model)\n  - [Ownership](#ownership)\n- [FAQ](#faq)\n  - [Where do I set up my app's roles and abilities?](#where-do-i-set-up-my-apps-roles-and-abilities)\n  - [Can I use a different set of roles & abilities for the public & dashboard sections of my site, respectively?](#can-i-use-a-different-set-of-roles--abilities-for-the-public--dashboard-sections-of-my-site-respectively)\n  - [I'm trying to run the migration, but I'm getting a SQL error that the \"specified key was too long\"](#im-trying-to-run-the-migration-but-im-getting-a-sql-error-that-the-specified-key-was-too-long)\n  - [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)\"](#im-trying-to-run-the-migration-but-im-getting-a-sql-error-that-there-is-a-syntax-error-or-access-violation-1064--to-use-near-json-not-null)\n- [Console commands](#console-commands)\n  - [`bouncer:clean`](#bouncerclean)\n- [Cheat sheet](#cheat-sheet)\n- [Alternative](#alternative)\n- [License](#license)\n\u003C\u002Fp>\u003C\u002Fdetails>\n\n## Introduction\n\nBouncer 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.\n\nFor a quick, glanceable list of Bouncer's features, check out [the cheat sheet](#cheat-sheet).\n\nBouncer 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.\n\nOnce installed, you can simply tell the bouncer what you want to allow at the gate:\n\n```php\n\u002F\u002F Give a user the ability to create posts\nBouncer::allow($user)->to('create', Post::class);\n\n\u002F\u002F Alternatively, do it through a role\nBouncer::allow('admin')->to('create', Post::class);\nBouncer::assign('admin')->to($user);\n\n\u002F\u002F You can also grant an ability only to a specific model\nBouncer::allow($user)->to('edit', $post);\n```\n\nWhen 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.\n\n## Installation\n\n> **Note**: Bouncer v1.0.2 requires PHP 8.2+ and Laravel\u002FEloquent 11+.\n>\n> If you're on Laravel v6-v10, use [Bouncer v1.0.1](https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Ftree\u002Fv1.0.1). If you're on Laravel v5.5-v5.8, use [Bouncer RC6](https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Ftree\u002Fv1.0.0-rc.6).\n\n### Installing Bouncer in a Laravel app\n\n1) Install Bouncer with [composer](https:\u002F\u002Fgetcomposer.org\u002Fdoc\u002F00-intro.md):\n\n    ```\n    composer require silber\u002Fbouncer\n    ```\n\n2) Add Bouncer's trait to your user model:\n\n    ```php\n    use Silber\\Bouncer\\Database\\HasRolesAndAbilities;\n\n    class User extends Model\n    {\n        use HasRolesAndAbilities;\n    }\n    ```\n\n3) Now, to run Bouncer's migrations. First publish the migrations into your app's `migrations` directory, by running the following command:\n\n    ```\n    php artisan vendor:publish --tag=\"bouncer.migrations\"\n    ```\n\n4) Finally, run the migrations:\n\n    ```\n    php artisan migrate\n    ```\n\n#### Facade\n\nWhenever you use the `Bouncer` facade in your code, remember to add this line to your namespace imports at the top of the file:\n\n```php\nuse Bouncer;\n```\n\nFor more information about Laravel Facades, refer to [the Laravel documentation](https:\u002F\u002Flaravel.com\u002Fdocs\u002F11.x\u002Ffacades).\n\n### Installing Bouncer in a non-Laravel app\n\n1) Install Bouncer with [composer](https:\u002F\u002Fgetcomposer.org\u002Fdoc\u002F00-intro.md):\n\n    ```\n    composer require silber\u002Fbouncer\n    ```\n\n2) Set up the database with [the Eloquent Capsule component](https:\u002F\u002Fgithub.com\u002Filluminate\u002Fdatabase\u002Fblob\u002Fmaster\u002FREADME.md):\n\n    ```php\n    use Illuminate\\Database\\Capsule\\Manager as Capsule;\n\n    $capsule = new Capsule;\n\n    $capsule->addConnection([\u002F* connection config *\u002F]);\n\n    $capsule->setAsGlobal();\n    ```\n\n    Refer to [the Eloquent Capsule documentation](https:\u002F\u002Fgithub.com\u002Filluminate\u002Fdatabase\u002Fblob\u002Fmaster\u002FREADME.md) for more details.\n\n3) Run the migrations by either of the following methods:\n\n    - Use a tool such as [vagabond](https:\u002F\u002Fgithub.com\u002Fmichaeldyrynda\u002Fvagabond) to run Laravel migrations outside of a Laravel app. You'll find the necessary migrations in [the migrations stub file](https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Fblob\u002Fmaster\u002Fmigrations\u002Fcreate_bouncer_tables.php#L18-L79).\n\n    - Alternatively, you can run [the raw SQL](https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Fblob\u002Fmaster\u002Fmigrations\u002Fsql\u002FMySQL.sql) directly in your database.\n\n4) Add Bouncer's trait to your user model:\n\n    ```php\n    use Illuminate\\Database\\Eloquent\\Model;\n    use Silber\\Bouncer\\Database\\HasRolesAndAbilities;\n\n    class User extends Model\n    {\n        use HasRolesAndAbilities;\n    }\n    ```\n\n5) Create an instance of Bouncer:\n\n    ```php\n    use Silber\\Bouncer\\Bouncer;\n\n    $bouncer = Bouncer::create();\n\n    \u002F\u002F If you are in a request with a current user\n    \u002F\u002F that you'd wish to check permissions for,\n    \u002F\u002F pass that user to the \"create\" method:\n    $bouncer = Bouncer::create($user);\n    ```\n\n    If you're using dependency injection in your app, you may register the `Bouncer` instance as a singleton in the container:\n\n    ```php\n    use Silber\\Bouncer\\Bouncer;\n    use Illuminate\\Container\\Container;\n\n    Container::getInstance()->singleton(Bouncer::class, function () {\n        return Bouncer::create();\n    });\n    ```\n\n    You can now inject `Bouncer` into any class that needs it.\n\n    The `create` method creates a `Bouncer` instance with sensible defaults. To fully customize it, use the `make` method to get a factory instance. Call `create()` on the factory to create the `Bouncer` instance:\n\n    ```php\n    use Silber\\Bouncer\\Bouncer;\n\n    $bouncer = Bouncer::make()\n             ->withCache($customCacheInstance)\n             ->create();\n    ```\n\n    Check out [the `Factory` class](https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Fblob\u002Fc974953a0b1d8d187023002cdfae1800f3ccdb02\u002Fsrc\u002FFactory.php) to see all the customizations available.\n\n6) Set which model is used as the user model throughout your app:\n\n    ```php\n    $bouncer->useUserModel(User::class);\n    ```\n\n    For additional configuration, check out [the Configuration section](#configuration) below.\n\n### Enabling cache\n\nBy default, Bouncer's queries are cached for the current request. For better performance, you may want to [enable cross-request caching](#cache).\n\n## Usage\n\nAdding 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\u002Fability, and Bouncer will create it if it doesn't exist.\n\n> **Note:** the examples below all use the `Bouncer` facade. If you don't use facades, you can instead inject an instance of `Silber\\Bouncer\\Bouncer` into your class.\n\n### Creating roles and abilities\n\nLet's create a role called `admin` and give it the ability to `ban-users` from our site:\n\n```php\nBouncer::allow('admin')->to('ban-users');\n```\n\nThat's it. Behind the scenes, Bouncer will create both a `Role` model and an `Ability` model for you.\n\nIf you want to add additional attributes to the role\u002Fability, such as a human-readable title, you can manually create them using the `role` and `ability` methods on the `Bouncer` class:\n\n```php\n$admin = Bouncer::role()->firstOrCreate([\n    'name' => 'admin',\n    'title' => 'Administrator',\n]);\n\n$ban = Bouncer::ability()->firstOrCreate([\n    'name' => 'ban-users',\n    'title' => 'Ban users',\n]);\n\nBouncer::allow($admin)->to($ban);\n```\n\n### Assigning roles to a user\n\nTo now give the `admin` role to a user, simply tell the bouncer that the given user should be assigned the admin role:\n\n```php\nBouncer::assign('admin')->to($user);\n```\n\nAlternatively, you can call the `assign` method directly on the user:\n\n```php\n$user->assign('admin');\n```\n\n### Giving a user an ability directly\n\nSometimes you might want to give a user an ability directly, without using a role:\n\n```php\nBouncer::allow($user)->to('ban-users');\n```\n\nHere too you can accomplish the same directly off of the user:\n\n```php\n$user->allow('ban-users');\n```\n\n### Restricting an ability to a model\n\nSometimes you might want to restrict an ability to a specific model type. Simply pass the model name as a second argument:\n\n```php\nBouncer::allow($user)->to('edit', Post::class);\n```\n\nIf you want to restrict the ability to a specific model instance, pass in the actual model instead:\n\n```php\nBouncer::allow($user)->to('edit', $post);\n```\n\n### Allowing a user or role to \"own\" a model\n\nUse the `toOwn` method to allow users to manage _their own_ models:\n\n```php\nBouncer::allow($user)->toOwn(Post::class);\n```\n\nNow, when checking at the gate whether the user may perform an action on a given post, the post's `user_id` will be compared to the logged-in user's `id` ([this can be customized](#ownership)). If they match, the gate will allow the action.\n\nThe above will grant all abilities on a user's \"owned\" models. You can restrict the abilities by following it up with a call to the `to` method:\n\n```php\nBouncer::allow($user)->toOwn(Post::class)->to('view');\n\n\u002F\u002F Or pass it an array of abilities:\nBouncer::allow($user)->toOwn(Post::class)->to(['view', 'update']);\n```\n\nYou can also allow users to own all _types_ of models in your application:\n\n```php\nBouncer::allow($user)->toOwnEverything();\n\n\u002F\u002F And to restrict ownership to a given ability\nBouncer::allow($user)->toOwnEverything()->to('view');\n```\n\n### Retracting a role from a user\n\nThe bouncer can also retract a previously-assigned role from a user:\n\n```php\nBouncer::retract('admin')->from($user);\n```\n\nOr do it directly on the user:\n\n```php\n$user->retract('admin');\n```\n\n### Removing an ability\n\nThe bouncer can also remove an ability previously granted to a user:\n\n```php\nBouncer::disallow($user)->to('ban-users');\n```\n\nOr directly on the user:\n\n```php\n$user->disallow('ban-users');\n```\n\n> **Note:** if the user has a role that allows them to `ban-users`, they will still have that ability. To disallow it, either remove the ability from the role or retract the role from the user.\n\nIf the ability has been granted through a role, tell the bouncer to remove the ability from the role instead:\n\n```php\nBouncer::disallow('admin')->to('ban-users');\n```\n\nTo remove an ability for a specific model type, pass in its name as a second argument:\n\n```php\nBouncer::disallow($user)->to('delete', Post::class);\n```\n\n> **Warning:** if the user has an ability to `delete` a specific `$post` instance, the code above will *not* remove that ability. You will have to remove the ability separately - by passing in the actual `$post` as a second argument - as shown below.\n\nTo remove an ability for a specific model instance, pass in the actual model instead:\n\n```php\nBouncer::disallow($user)->to('delete', $post);\n```\n\n> **Note**: the `disallow` method only removes abilities that were previously given to this user\u002Frole. If you want to disallow a subset of what a more-general ability has allowed, use [the `forbid` method](#forbidding-an-ability).\n\n### Forbidding an ability\n\nBouncer also allows you to `forbid` a given ability, for more fine-grained control. At times you may wish to grant a user\u002Frole an ability that covers a wide range of actions, but then restrict a small subset of those actions.\n\nHere are some examples:\n\n- 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:\n\n    ```php\n    Bouncer::allow($user)->to('view', Document::class);\n\n    Bouncer::forbid($user)->to('view', $classifiedDocument);\n    ```\n\n- You may wish to allow your `superadmin`s to do everything in your app, including adding\u002Fremoving users. Then you may have an `admin` role that can do everything _besides_ managing users:\n\n    ```php\n    Bouncer::allow('superadmin')->everything();\n\n    Bouncer::allow('admin')->everything();\n    Bouncer::forbid('admin')->toManage(User::class);\n    ```\n\n- 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.\n\n    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 special `banned` role, for which we'll forbid everything:\n\n    ```php\n    Bouncer::forbid('banned')->everything();\n    ```\n\n    Then, whenever we want to ban a user, we'll assign them the `banned` role:\n\n    ```php\n    Bouncer::assign('banned')->to($user);\n    ```\n\n    To remove the ban, we'll simply retract the role from the user:\n\n    ```php\n    Bouncer::retract('banned')->from($user);\n    ```\n\nAs you can see, Bouncer's forbidden abilities gives you a lot of granular control over the permissions in your app.\n\n### Unforbidding an ability\n\nTo remove a forbidden ability, use the `unforbid` method:\n\n```php\nBouncer::unforbid($user)->to('view', $classifiedDocument);\n```\n\n> **Note**: this will remove any previously-forbidden ability. It will _not_ authomatically allow the ability if it's not already allowed by a different regular ability granted to this user\u002Frole.\n\n### Checking a user's roles\n\n> **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, an `access-dashboard` ability is always better than checking for `admin` or `editor` roles directly. For the rare occasion that you do want to check a role, that functionality is available here.\n\nThe bouncer can check if a user has a specific role:\n\n```php\nBouncer::is($user)->a('moderator');\n```\n\nIf the role you're checking starts with a vowel, you might want to use the `an` alias method:\n\n```php\nBouncer::is($user)->an('admin');\n```\n\nFor the inverse, you can also check if a user *doesn't* have a specific role:\n\n```php\nBouncer::is($user)->notA('moderator');\n\nBouncer::is($user)->notAn('admin');\n```\n\nYou can check if a user has one of many roles:\n\n```php\nBouncer::is($user)->a('moderator', 'editor');\n```\n\nYou can also check if the user has all of the given roles:\n\n```php\nBouncer::is($user)->all('editor', 'moderator');\n```\n\nYou can also check if a user has none of the given roles:\n\n```php\nBouncer::is($user)->notAn('editor', 'moderator');\n```\n\nThese checks can also be done directly on the user:\n\n```php\n$user->isAn('admin');\n$user->isA('subscriber');\n\n$user->isNotAn('admin');\n$user->isNotA('subscriber');\n\n$user->isAll('editor', 'moderator');\n```\n\n### Querying users by their roles\n\nYou can query your users by whether they have a given role:\n\n```php\n$users = User::whereIs('admin')->get();\n```\n\nYou may also pass in multiple roles, to query for users that have _any_ of the given roles:\n\n```php\n$users = User::whereIs('superadmin', 'admin')->get();\n```\n\nTo query for users who have _all_ of the given roles, use the `whereIsAll` method:\n\n```php\n$users = User::whereIsAll('sales', 'marketing')->get();\n```\n\n### Getting all roles for a user\n\nYou can get all roles for a user directly from the user model:\n\n```php\n$roles = $user->getRoles();\n```\n\n### Getting all abilities for a user\n\nYou can get all abilities for a user directly from the user model:\n\n```php\n$abilities = $user->getAbilities();\n```\n\nThis will return a collection of the user's allowed abilities, including any abilities granted to the user through their roles.\n\nYou can also get a list of abilities that have been _explicitly_ forfidden:\n\n```php\n$forbiddenAbilities = $user->getForbiddenAbilities();\n```\n\n### Authorizing users\n\nAuthorizing users is handled directly at [Laravel's `Gate`](https:\u002F\u002Flaravel.com\u002Fdocs\u002F11.x\u002Fauthorization#gates), or on the user model (`$user->can($ability)`).\n\nFor convenience, the `Bouncer` class provides these passthrough methods:\n\n```php\nBouncer::can($ability);\nBouncer::can($ability, $model);\n\nBouncer::canAny($abilities);\nBouncer::canAny($abilities, $model);\n\nBouncer::cannot($ability);\nBouncer::cannot($ability, $model);\n\nBouncer::authorize($ability);\nBouncer::authorize($ability, $model);\n```\n\nThese call directly into their equivalent methods on the `Gate` class.\n\n### Blade directives\n\nBouncer does not add its own blade directives. Since Bouncer works directly with Laravel's gate, simply use its `@can` directive to check for the current user's abilities:\n\n```html\n@can ('update', $post)\n    \u003Ca href=\"{{ route('post.update', $post) }}\">Edit Post\u003C\u002Fa>\n@endcan\n```\n\nSince checking for roles directly is generally [not recommended](#checking-a-users-roles), 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 `@if` directive:\n\n```php\n@if ($user->isAn('admin'))\n    \u002F\u002F\n@endif\n```\n\n### Refreshing the cache\n\nAll queries executed by Bouncer are cached for the current request. If you enable [cross-request caching](#cache), the cache will persist across different requests.\n\nWhenever you need, you can fully refresh the bouncer's cache:\n\n```php\nBouncer::refresh();\n```\n\n> **Note:** fully refreshing the cache for all users uses [cache tags](https:\u002F\u002Flaravel.com\u002Fdocs\u002F11.x\u002Fcache#cache-tags) if they're available. Not all cache drivers support this. Refer to [Laravel's documentation](https:\u002F\u002Flaravel.com\u002Fdocs\u002F11.x\u002Fcache#cache-tags) to see if your driver supports cache tags. If your driver does not support cache tags, calling `refresh` might be a little slow, depending on the amount of users in your system.\n\nAlternatively, you can refresh the cache only for a specific user:\n\n```php\nBouncer::refreshFor($user);\n```\n\n> **Note**: When using [multi-tenancy scopes](#multi-tenancy), 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.\n\n## Multi-tenancy\n\nBouncer fully supports multi-tenant apps, allowing you to seamlessly integrate Bouncer's roles and abilities for all tenants within the same app.\n\n### The scope middleware\n\nTo get started, first publish [the scope middleware](https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Fblob\u002Fmaster\u002Fmiddleware\u002FScopeBouncer.php) into your app:\n\n```\nphp artisan vendor:publish --tag=\"bouncer.middleware\"\n```\n\nThe middleware will now be published to `app\u002FHttp\u002FMiddleware\u002FScopeBouncer.php`. This middleware is where you tell Bouncer which tenant to use for the current request. For example, assuming your users all have an `account_id` attribute, this is what your middleware would look like:\n\n```php\npublic function handle($request, Closure $next)\n{\n    $tenantId = $request->user()->account_id;\n\n    Bouncer::scope()->to($tenantId);\n\n    return $next($request);\n}\n```\n\nYou 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.\n\nNow with the middleware in place, be sure to register it in your [HTTP Kernel](https:\u002F\u002Fgithub.com\u002Flaravel\u002Flaravel\u002Fblob\u002F73cff166c79cdeaef1c6b7ec6e71a33a7ea3012d\u002Fapp\u002FHttp\u002FKernel.php#L30-L38):\n\n```php\nprotected $middlewareGroups = [\n    'web' => [\n        \u002F\u002F Keep the existing middleware here, and add this:\n        \\App\\Http\\Middleware\\ScopeBouncer::class,\n    ]\n];\n```\n\nAll of Bouncer's queries will now be scoped to the given tenant.\n\n### Customizing Bouncer's scope\n\nDepending on your app's setup, you may not actually want _all_ of the queries to be scoped to the current tenant. For example, you may have a fixed set of roles\u002Fabilities 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:\n\n```php\nBouncer::scope()->to($tenantId)->onlyRelations();\n```\n\nFurthermore, 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:\n\n```php\nBouncer::scope()->to($tenantId)->onlyRelations()->dontScopeRoleAbilities();\n```\n\nIf your needs are even more specialized than what's outlined above, you can create your own [`Scope`](https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Fblob\u002Fab2b92d4d2379be3220daaf0d4185ea10237ff2b\u002Fsrc\u002FContracts\u002FScope.php) with whatever custom logic you need:\n\n```php\nuse Silber\\Bouncer\\Contracts\\Scope;\n\nclass MyScope implements Scope\n{\n    \u002F\u002F Whatever custom logic your app needs\n}\n```\n\nThen, in a service provider, register your custom scope:\n\n```php\nBouncer::scope(new MyScope);\n```\n\nBouncer will call the methods on the `Scope` interface at various points in its execution. You are free to handle them according to your specific needs.\n\n## Configuration\n\nBouncer 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 the `Bouncer` class.\n\nIf you only use one or two of these config options, you can stick them into your [main `AppServiceProvider`'s `boot` method](https:\u002F\u002Fgithub.com\u002Flaravel\u002Flaravel\u002Fblob\u002Fe077976680bdb2644698fb8965a1e2a8710b5d4b\u002Fapp\u002FProviders\u002FAppServiceProvider.php#L24-L27). If they start growing, you may create a separate `BouncerServiceProvider` class in [your `app\u002FProviders` directory](https:\u002F\u002Fgithub.com\u002Flaravel\u002Flaravel\u002Ftree\u002Fe077976680bdb2644698fb8965a1e2a8710b5d4b\u002Fapp\u002FProviders) (remember to register it in [the `providers` config array](https:\u002F\u002Fgithub.com\u002Flaravel\u002Flaravel\u002Fblob\u002Fe077976680bdb2644698fb8965a1e2a8710b5d4b\u002Fconfig\u002Fapp.php#L171-L178)).\n\n### Cache\n\nBy default, all queries executed by Bouncer are cached for the current request. For better performance, you may want to use cross-request caching:\n\n```php\nBouncer::cache();\n```\n\n> **Warning:** if you enable cross-request caching, you are responsible to refresh the cache whenever you make changes to user's roles\u002Fabilities. For how to refresh the cache, read [refreshing the cache](#refreshing-the-cache).\n\nOn the contrary, you may at times wish to _completely disable_ the cache, even within the same request:\n\n```php\nBouncer::dontCache();\n```\n\nThis is particularly useful in unit tests, when you want to run assertions against roles\u002Fabilities that have just been granted.\n\n### Tables\n\nTo change the database table names used by Bouncer, pass an associative array to the `tables` method. 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.\n\n```php\nBouncer::tables([\n    'abilities' => 'my_abilities',\n    'permissions' => 'granted_abilities',\n]);\n```\n\nBouncer's published migration uses the table names from this configuration, so be sure to have these in place before actually running the migration.\n\n### Custom models\n\nYou can easily extend Bouncer's built-in `Role` and `Ability` models:\n\n```php\nnamespace App\\Models;\n\nuse Silber\\Bouncer\\Database\\Ability as BouncerAbility;\n\nclass Ability extends BouncerAbility\n{\n    \u002F\u002F custom code\n}\n```\n\n```php\nnamespace App\\Models;\n\nuse Silber\\Bouncer\\Database\\Role as BouncerRole;\n\nclass Role extends BouncerRole\n{\n    \u002F\u002F custom code\n}\n```\n\nAlternatively, you can use Bouncer's `IsAbility` and `IsRole` traits without actually extending any of Bouncer's models:\n\n```php\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Silber\\Bouncer\\Database\\Concerns\\IsAbility;\n\nclass Ability extends Model\n{\n    use IsAbility;\n\n    \u002F\u002F custom code\n}\n```\n\n```php\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Silber\\Bouncer\\Database\\Concerns\\IsRole;\n\nclass Role extends Model\n{\n    use IsRole;\n\n    \u002F\u002F custom code\n}\n```\n\nIf you use the traits instead of extending Bouncer's models, be sure to set the proper `$table` name and `$fillable` fields yourself.\n\nRegardless of which method you use, the next step is to actually tell Bouncer to use your custom models:\n\n```php\nBouncer::useAbilityModel(\\App\\Models\\Ability::class);\nBouncer::useRoleModel(\\App\\Models\\Role::class);\n```\n\n> **Note**: Eloquent determines the foreign key of relationships based on the parent model name (see [the Eloquent docs](https:\u002F\u002Flaravel.com\u002Fdocs\u002F11.x\u002Feloquent-relationships#one-to-one)). To keep things simple, name your custom classes the same as Bouncer's: `Ability` and `Role`, respectively.\n>\n> 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.\n\n### User Model\n\nBy default, Bouncer automatically [uses the user model of the default auth guard](https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Fblob\u002F462f312\u002Fsrc\u002FBouncerServiceProvider.php#L171-L190).\n\nIf 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:\n\n```php\nBouncer::useUserModel(\\App\\Admin::class);\n```\n\n### Ownership\n\nIn Bouncer, the concept of ownership is used to [allow users to perform actions on models they \"own\"](#allowing-a-user-or-role-to-own-a-model).\n\nBy default, Bouncer will check the model's `user_id` against the current user's primary key. If needed, this can be set to a different attribute:\n\n```php\nBouncer::ownedVia('userId');\n```\n\nIf different models use different columns for ownership, you can register them separately:\n\n```php\nBouncer::ownedVia(Post::class, 'created_by');\nBouncer::ownedVia(Order::class, 'entered_by');\n```\n\nFor greater control, you can pass a closure with your custom logic:\n\n```php\nBouncer::ownedVia(Game::class, function ($game, $user) {\n    return $game->team_id == $user->team_id;\n});\n```\n\n## FAQ\n\nThere are some concepts in Bouncer that people keep on asking about, so here's a short list of some of those topics:\n\n### Where do I set up my app's roles and abilities?\n\nSeeding the initial roles and abilities can be done in a regular [Laravel seeder](https:\u002F\u002Flaravel.com\u002Fdocs\u002F11.x\u002Fseeding) class. Start by creating a specific seeder file for Bouncer:\n\n```\nphp artisan make:seeder BouncerSeeder\n```\n\nPlace all of your seeding roles & abilities code in [the seeder's `run` method](https:\u002F\u002Fgithub.com\u002Flaravel\u002Fframework\u002Fblob\u002Ff50e2004dfa40de895cd841a0a94acef5b417900\u002Fsrc\u002FIlluminate\u002FDatabase\u002FConsole\u002FSeeds\u002Fstubs\u002Fseeder.stub#L12-L15). Here's an example of what that might look like:\n\n```php\nuse Bouncer;\nuse Illuminate\\Database\\Seeder;\n\nclass BouncerSeeder extends Seeder\n{\n    public function run()\n    {\n        Bouncer::allow('superadmin')->everything();\n\n        Bouncer::allow('admin')->everything();\n        Bouncer::forbid('admin')->toManage(User::class);\n\n        Bouncer::allow('editor')->to('create', Post::class);\n        Bouncer::allow('editor')->toOwn(Post::class);\n\n        \u002F\u002F etc.\n    }\n}\n```\n\n\nTo actually run it, pass the seeder's class name to the `class` option of the `db:seed` command:\n\n```\nphp artisan db:seed --class=BouncerSeeder\n```\n\n### Can I use a different set of roles & abilities for the public & dashboard sections of my site, respectively?\n\nBouncer's [`scope`](#the-scope-middleware) can 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:\n\n1. Create a `ScopeBouncer` [middleware](https:\u002F\u002Flaravel.com\u002Fdocs\u002F11.x\u002Fmiddleware#defining-middleware) that takes an `$identifier` and sets it as the current scope:\n\n    ```php\n    use Bouncer, Closure;\n\n    class ScopeBouncer\n    {\n        public function handle($request, Closure $next, $identifier)\n        {\n            Bouncer::scope()->to($identifier);\n\n            return $next($request);\n        }\n    }\n    ```\n\n2. Register this new middleware as a route middleware in your [HTTP Kernel class](https:\u002F\u002Fgithub.com\u002Flaravel\u002Flaravel\u002Fblob\u002F73cff166c79cdeaef1c6b7ec6e71a33a7ea3012d\u002Fapp\u002FHttp\u002FKernel.php#L53-L60):\n\n    ```php\n    protected $routeMiddleware = [\n        \u002F\u002F Keep the other route middleware, and add this:\n        'scope-bouncer' => \\App\\Http\\Middleware\\ScopeBouncer::class,\n    ];\n    ```\n\n3. In your [route service provider](https:\u002F\u002Fgithub.com\u002Flaravel\u002Flaravel\u002Fblob\u002F73cff166c79cdeaef1c6b7ec6e71a33a7ea3012d\u002Fapp\u002FProviders\u002FRouteServiceProvider.php), apply this middleware with a different identifier for the public routes and the dashboard routes, respectively:\n\n    ```php\n    Route::middleware(['web', 'scope-bouncer:1'])\n         ->namespace($this->namespace)\n         ->group(base_path('routes\u002Fpublic.php'));\n\n    Route::middleware(['web', 'scope-bouncer:2'])\n         ->namespace($this->namespace)\n         ->group(base_path('routes\u002Fdashboard.php'));\n    ```\n\nThat'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, see [Customizing Bouncer's scope](#customizing-bouncers-scope).\n\n### I'm trying to run the migration, but I'm getting a SQL error that the \"specified key was too long\"\n\nStarting with Laravel 5.4, the default database character set is now `utf8mb4`. 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 your `AppServiceProvider`:\n\n```php\nuse Illuminate\\Support\\Facades\\Schema;\n\npublic function boot()\n{\n    Schema::defaultStringLength(191);\n}\n```\n\nYou can read more in [this Laravel News article](https:\u002F\u002Flaravel-news.com\u002Flaravel-5-4-key-too-long-error).\n\n## 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)\"\n\nJSON 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.\n\nThe best solution would be to upgrade your DB. If that's not currently possible, you can change [your published migration file](https:\u002F\u002Fgithub.com\u002FJosephSilber\u002Fbouncer\u002Fblob\u002F2e31b84e9c1f6c2b86084df2af9d05299ba73c62\u002Fmigrations\u002Fcreate_bouncer_tables.php#L25) to use a `text` column instead:\n\n```diff\n- $table->json('options')->nullable();\n+ $table->text('options')->nullable();\n```\n\n## Console commands\n\n### `bouncer:clean`\n\nThe `bouncer:clean` command deletes unused abilities. Running this command will delete 2 types of unused abilities:\n\n- **Unassigned abilities** - abilities that are not assigned to anyone. For example:\n\n    ```php\n    Bouncer::allow($user)->to('view', Plan::class);\n\n    Bouncer::disallow($user)->to('view', Plan::class);\n    ```\n\n    At this point, the \"view plans\" ability is not assigned to anyone, so it'll get deleted.\n\n    > **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 probably _don't_ want to delete unassigned abilities. See below.\n\n- **Orphaned abilities** - model abilities whose models have been deleted:\n\n    ```php\n    Bouncer::allow($user)->to('delete', $plan);\n\n    $plan->delete();\n    ```\n\n    Since the plan no longer exists, the ability is no longer of any use, so it'll get deleted.\n\nIf you only want to delete one type of unused ability, run it with one of the following flags:\n\n```\nphp artisan bouncer:clean --unassigned\nphp artisan bouncer:clean --orphaned\n```\n\nIf you don't pass it any flags, it will delete both types of unused abilities.\n\nTo automatically run this command periodically, add it to [your console kernel's schedule](https:\u002F\u002Flaravel.com\u002Fdocs\u002F11.x\u002Fscheduling#defining-schedules):\n\n```php\n$schedule->command('bouncer:clean')->weekly();\n```\n\n## Cheat Sheet\n\n```php\n\u002F\u002F Adding abilities for users\nBouncer::allow($user)->to('ban-users');\nBouncer::allow($user)->to('edit', Post::class);\nBouncer::allow($user)->to('delete', $post);\n\nBouncer::allow($user)->everything();\nBouncer::allow($user)->toManage(Post::class);\nBouncer::allow($user)->toManage($post);\nBouncer::allow($user)->to('view')->everything();\n\nBouncer::allow($user)->toOwn(Post::class);\nBouncer::allow($user)->toOwnEverything();\n\n\u002F\u002F Removing abilities uses the same syntax, e.g.\nBouncer::disallow($user)->to('delete', $post);\nBouncer::disallow($user)->toManage(Post::class);\nBouncer::disallow($user)->toOwn(Post::class);\n\n\u002F\u002F Adding & removing abilities for roles\nBouncer::allow('admin')->to('ban-users');\nBouncer::disallow('admin')->to('ban-users');\n\n\u002F\u002F You can also forbid specific abilities with the same syntax...\nBouncer::forbid($user)->to('delete', $post);\n\n\u002F\u002F And also remove a forbidden ability with the same syntax...\nBouncer::unforbid($user)->to('delete', $post);\n\n\u002F\u002F Re-syncing a user's abilities\nBouncer::sync($user)->abilities($abilities);\n\n\u002F\u002F Assigning & retracting roles from users\nBouncer::assign('admin')->to($user);\nBouncer::retract('admin')->from($user);\n\n\u002F\u002F Assigning roles to multiple users by ID\nBouncer::assign('admin')->to([1, 2, 3]);\n\n\u002F\u002F Re-syncing a user's roles\nBouncer::sync($user)->roles($roles);\n\n\u002F\u002F Checking the current user's abilities\n$boolean = Bouncer::can('ban-users');\n$boolean = Bouncer::can('edit', Post::class);\n$boolean = Bouncer::can('delete', $post);\n\n$boolean = Bouncer::cannot('ban-users');\n$boolean = Bouncer::cannot('edit', Post::class);\n$boolean = Bouncer::cannot('delete', $post);\n\n\u002F\u002F Checking a user's roles\n$boolean = Bouncer::is($user)->a('subscriber');\n$boolean = Bouncer::is($user)->an('admin');\n$boolean = Bouncer::is($user)->notA('subscriber');\n$boolean = Bouncer::is($user)->notAn('admin');\n$boolean = Bouncer::is($user)->a('moderator', 'editor');\n$boolean = Bouncer::is($user)->all('moderator', 'editor');\n\nBouncer::cache();\nBouncer::dontCache();\n\nBouncer::refresh();\nBouncer::refreshFor($user);\n```\n\nSome of this functionality is also available directly on the user model:\n\n```php\n$user->allow('ban-users');\n$user->allow('edit', Post::class);\n$user->allow('delete', $post);\n\n$user->disallow('ban-users');\n$user->disallow('edit', Post::class);\n$user->disallow('delete', $post);\n\n$user->assign('admin');\n$user->retract('admin');\n\n$boolean = $user->isAn('admin');\n$boolean = $user->isAn('editor', 'moderator');\n$boolean = $user->isAll('moderator', 'editor');\n$boolean = $user->isNotAn('admin', 'moderator');\n\n\u002F\u002F Querying users by their roles\n$users = User::whereIs('superadmin')->get();\n$users = User::whereIs('superadmin', 'admin')->get();\n$users = User::whereIsAll('sales', 'marketing')->get();\n\n$abilities = $user->getAbilities();\n$forbidden = $user->getForbiddenAbilities();\n```\n\n## Alternative\n\nAmong the bajillion packages that [Spatie](https:\u002F\u002Fspatie.be) has so graciously bestowed upon the community, you'll find the excellent [laravel-permission](https:\u002F\u002Fgithub.com\u002Fspatie\u002Flaravel-permission) package. 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.\n\n## License\n\nBouncer is open-sourced software licensed under the [MIT license](http:\u002F\u002Fopensource.org\u002Flicenses\u002FMIT)\n","Bouncer 是一个用于 Laravel Eloquent 模型的角色和权限管理库。它提供了一种优雅且框架无关的方式来处理用户角色分配、直接授予权限以及对特定模型的访问控制，支持多租户环境下的细粒度权限设置。通过 Bouncer，开发者可以轻松地为应用程序添加复杂的权限逻辑，包括但不限于创建角色与能力、为用户分配角色或直接赋予能力、限制某些操作到特定的数据模型上等。此外，Bouncer 还提供了缓存功能以提高性能，并且兼容非 Laravel 项目。此工具非常适合需要灵活而强大的访问控制机制的企业级应用开发场景。",2,"2026-06-11 03:18:17","top_language"]