{"id":21893720,"url":"https://github.com/micc83/rooles","last_synced_at":"2025-10-07T18:03:55.396Z","repository":{"id":36843700,"uuid":"41150634","full_name":"micc83/rooles","owner":"micc83","description":"A very simple package to handle Roles and Permissions in Laravel 5.1","archived":false,"fork":false,"pushed_at":"2023-04-19T20:49:53.000Z","size":297,"stargazers_count":11,"open_issues_count":4,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-09-08T20:38:26.941Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/micc83.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-08-21T10:39:09.000Z","updated_at":"2023-10-12T05:50:03.000Z","dependencies_parsed_at":"2025-04-16T09:05:44.516Z","dependency_job_id":null,"html_url":"https://github.com/micc83/rooles","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/micc83/rooles","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micc83%2Frooles","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micc83%2Frooles/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micc83%2Frooles/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micc83%2Frooles/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/micc83","download_url":"https://codeload.github.com/micc83/rooles/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micc83%2Frooles/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278820733,"owners_count":26051767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-28T13:16:23.297Z","updated_at":"2025-10-07T18:03:55.359Z","avatar_url":"https://github.com/micc83.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Laravel Rooles [![Build Status](https://travis-ci.org/micc83/rooles.svg?branch=master)](https://travis-ci.org/micc83/rooles) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/micc83/rooles/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/micc83/rooles/?branch=master)\n-------------\n#### Simple roles and permissions manager for Laravel ^7.0\n\n### Why another Laravel RBAC (Role based access control) ?!?\n\nWell, good point! Most of the ACL systems out here such as [romanbican/roles](https://github.com/romanbican/roles), [kodeine/laravel-acl](https://github.com/kodeine/laravel-acl) or [Sentinel](https://cartalyst.com/manual/sentinel/) are packed with tons of amazing features... which most of the time I'm not using! :D\n\nThat's why I thought to build a minimal **Laravel roles and permissions manager** that provides a very simple RBAC implementation.\nEach user can be assigned a single Role, while permissions for each Role are stored in a single config file. With the package are provided a very intuitive and well documented API, a Trait to check permissions directly on the Eloquent User Model and two Middlewares to easily protect routes and Controllers.\n\nHowever, as your application grown, you might need a more complex ACL system, that's why the package comes with a couple of Contracts that you can leverage to improve or replace functionalities at need. You can see **Rooles** not only as a fully working RBAC but also as a *starting point to develop your own custom roles and permission manager*.\n\n### Setup\n\nRun the following from your terminal from within the path containing the Laravel `composer.json` file:\n\n```sh\n$ composer require micc83/rooles\n```\n\nOpen `config/app.php` and add the following line at the end of the providers array:\n\n```php\nRooles\\RoolesServiceProvider::class\n```\n\nRun the following command from your terminal to publish the migration file (it will simply add a `role` column to the default Users table), the config file and a default blade template for the *403-Forbidden* view (It will not be published if one has already been created):\n\n```sh\n$ php artisan vendor:publish\n```\n\nIn order to be able to use route and Controllers middlewares (so to be able to filter who's able to access a given route or Controller method) open `App/Http/Kernel.php` and add the following lines at the end of the `$routeMiddleware` array:\n\n```php\n'perms' =\u003e \\Rooles\\PermsMiddleware::class,\n'role'  =\u003e \\Rooles\\RoleMiddleware::class,\n```\n\nAs **Rooles** works on top of the default *Auth* system of Laravel and with the *Eloquent* User Model you must add the `Rooles\\Traits\\UserRole` trait to the User Class located in `App/User.php` as follow:\n\n```php\nuse \\Rooles\\Traits\\UserRole;\n\nclass User extends Model implements AuthenticatableContract, CanResetPasswordContract\n{\n\n    use Authenticatable, CanResetPassword, UserRole;\n\n    // ...\n}\n```\n\n\u003e **Important note on Laravel version \u003e= 1.1.11** From this version on Laravel implements its own permission manager trough the `Authorizable` trait/contract so, in order to have the User model work with Rooles, you must remove any reference to both the `Authorizable` trait and interface from the Eloquent user model.\n\n### Setting up users role\n\nOnly a single Role can be assigned to each User. You can hardcode the role inside the User Eloquent model adding the role attribute as follow:\n\n```php\nprotected $attributes = [\n    'role' =\u003e 'admin'\n];\n```\n\nOr run the provided migration to add the `role` column to the Users Table so to be able to change Users role at runtime:\n\n```php\n$user = User::find(1);\n$user-\u003erole = 'admin';\n$user-\u003esave();\n```\n\n### Setting up permissions\n\nAll the permissions for any given role are set in the `config/rooles.php` file as follow:\n\n```php\n\u003c?php return [\n    'roles' =\u003e [\n        'default' =\u003e []\n        'admin' =\u003e [\n            'name' =\u003e 'Administrator',\n            'grant' =\u003e '*'\n        ],\n        'editor' =\u003e [\n            'grant' =\u003e [\n                'posts.*',\n                'users.*.read',\n                'users.*.ban',\n                'comments.*',\n                'profile.*'\n            ],\n            'deny' =\u003e [\n                'users.admin.ban',\n                'posts.delete',\n                'comments.delete'\n            ]\n        ]\n    ]\n];\n```\n\nAs you can see the format used is:\n\n```php\n[\n    'roles' =\u003e [\n        'role_id' =\u003e [\n            'name' =\u003e 'role_name',\n            'grant' =\u003e 'string_or_array_of_granted_permissions',\n            'deny' =\u003e 'string_or_array_of_denied_permissions',\n        ]\n    ]\n]\n```\n\nThe `default` role is applied to any user which has no role applied and provides no permissions unless differently stated in the config file.\n\nThe `name` property is optional and allows to set a name differing from the provided Role ID.\n\nYou can also create roles and handle permissions manually. Here's an example:\n\n```php\napp()-\u003emake(\\Rooles\\Contracts\\RoleRepository::class)\n     -\u003egetOrCreate('customer')\n     -\u003eassignName('Client')\n     -\u003egrant(['cart.*', 'products.buy'])\n     -\u003edeny('cart.discount');\n```\n\n### Permissions strategy\n\nThere are four main concept to remember when creating a permissions strategy for **Rooles**:\n\n1. Every role always start with **no permissions**;\n2. The **wildcard character** \\* is used to define a whole subset of available permissions. For example if we take in consideration the grant `users.*.ban`, that means that editors can ban any group of users ( `users.reader`, `users.author` etc... ) but not `users.admin` as the permission has been denied in the deny array.\n3. When you grant or deny a permission, if not already set, a *wildcard will be automatically appended* so `customers` is the same as `customers.*`. That also means that any child permission of the given one will be granted or denied, for example:\n    ```php\n        $role-\u003egrant('comments'); // Same as writing comments.*\n\n        $role-\u003ecan('comments.write'); // true\n        $role-\u003ecan('comments.pingbacks.write') // true\n    ```\n4. When you apply both grants and denies in order to figure out which rule will 'win' you'll have to think in terms of **specificity**. The more specific rule will always win. Let's see an example:\n    ```php\n        $role-\u003egrant('comments.write.*') // Same as writing comments.write\n             -\u003edeny('*.write');\n\n        $role-\u003ecan('comments.write'); // true\n        $role-\u003ecan('users.write') // false\n    ```\nAs you probably guessed from the example specificity is calculated on the position of the wildcards and length of the permission. As you move the wildcard to the right you gain in specificity.\n\n### Checking for User permissions\n\nFrom within your Controller methods or wherever you feel comfortable you can check for a given user permissions as follow:\n\n```php\n$user = User::find(1);\nif ($user-\u003ecan('comments.post')){\n    // Do something...\n}\n```\n\nThe same to check the logged in user permissions:\n\n```php\npublic function index(Illuminate\\Contracts\\Auth\\Guard $auth) {\n\n    if ( $auth-\u003euser-\u003ecan('users.list') ){\n        // Do something...\n    }\n\n}\n```\n\nThe API exposes a convenient method to negate a permissions assertion:\n\n```php\nif ( $user-\u003ecannot('users.list') ) redirect()-\u003eto('dashboard');\n```\n\nYou can evaluate multiple assertions passing an array through:\n\n```php\nif ( $user-\u003ecan(['users.list', 'users.read']) ) // Do something when the user has both the permissions (AND)\n```\n\nThere are also two convenient operator to use with the can/cannot assertions:\n\n```php\nif ( $user-\u003ecan('users.list\u0026users.read') ) // Do something when the user has both the permissions (\u0026 \u003e AND)\nif ( $user-\u003ecan('users.list|users.read') ) // Do something when the user has one of the requested permissions (| \u003e OR)\n```\n\nMultiple operators can ben be joined together but mind that AND operators have always priority over OR operators.\n\n### Checking for User role\n\nYou can make a more general assertion checking for the user role ID (case insensitive):\n\n```php\nif ( $user-\u003erole-\u003eis('admin') ) echo 'Hello Boss';\n```\n\nOr check if the user role ID is in a given range (still case insensitive):\n\n```php\nif ( $user-\u003erole-\u003eisIn(['lamer', 'trool']) ) echo 'Hello Looser';\n```\n\nYou can also get the User role name (the ID will be returned if no name is provided), using one of the following syntax:\n\n```php\n// If in a string context:\necho $user-\u003erole;\n// Otherwise:\nif ($user-\u003erole-\u003ename() === 'Admin') // Do something\n```\n\nIf you need to make some comparisons, like for example in a Select input field you better use the ID instead of the name. Example:\n\n```php\n{!! Form::select('role', ['editor' =\u003e 'Editor', 'admin' =\u003e 'Administrator'], $user-\u003erole-\u003eid()) !!}\n```\n\n\u003e Remember that role ID is automatically converted to lowercase with UTF8 support.\n\n### Protect routes and Controllers through Middlewares\n\n**Rooles** provides two Middlewares to protect both routes and Controllers.\n\nTo protect routes by User Role you can use the **role Middleware**:\n\n```php\nRoute::get('admin/users/', [\n    'middleware' =\u003e [\n        'auth',\n        'role:admin|editor', // Give access to both admins and editors\n    ],\n    function () {\n        return view('admin.users.index');\n    }\n]);\n```\n\nIn order to check for user permissions on a route you can use the **perms Middleware** as follow:\n\n```php\nRoute::get('admin/users/', [\n    'middleware' =\u003e [\n        'auth',\n        'perms:users.list|users.edit', // Give access to users with users.list OR users.edit permissions\n    ]\n    function () {\n        return view('admin.users.index');\n    }\n]);\n```\n\nIn both case you'll have probably noticed that I'm calling the **Auth middleware** as the user must be logged in in order to check its Role and permissions.\n\nMost of the times you'll be probably being dealing with routes groups, in that case you can simply:\n\n```php\n// Route Group\nRoute::group([\n    'middleware' =\u003e [\n        'auth',\n        'role:admin|editor' // Give access to both admins and editors\n    ]\n], function () {\n    Route::resource('users', 'UserController');\n    Route::resource('posts', 'PostController');\n});\n```\n\nMiddlewares can also be used in Controllers as follow:\n\n```php\nclass UserController extends Controller\n{\n\n    /**\n     * @var UserRepository\n     */\n    private $users;\n\n    /**\n     * @param UserRepo $users\n     */\n    public function __construct(UserRepository $users)\n    {\n        $this-\u003eusers = $users;\n        $this-\u003emiddleware('perms:users', ['except' =\u003e 'show']);\n    }\n```\n\nHere we are saying that in order to access any controller method we must have a role that provides all the `users` permissions but we don't need any permission to show user profiles. You can find a better documentation on Controller Middlewares on the official [Laravel website](http://laravel.com/docs/5.0/controllers#controller-middleware).\n\n#### Handling middlewares HTTP error responses\n\n**Rooles** middlewares handles error responses differently depending on the nature of the request. For Ajax requests they will respond with a JSON Object and a `403` status code as follow:\n\n```json\n{\n    \"error\" : {\n        \"code\" : 403,\n        \"message\" : \"Forbidden\"\n    }\n}\n```\n\nSo that you can intercept it in JavaScript as follow:\n\n```js\nif ('error' in response) console.log(response.error.message);\n```\n\nFor normal requests in case of missing authorizations a `Rooles\\ForbiddenHttpException` is thrown, which by default (when debug is disabled) will result in the previously published 403 error page with a `403` status code. The page itself can be customized editing the `resources/views/errors/403.blade.php` template.\n\nOtherwise if you'd rather not to show a view but instead implement some custom behaviour you can play with the render method in `app/Exceptions/Handler.php` as follow:\n\n```php\npublic function render($request, Exception $e)\n{\n    if ($e instanceof \\Rooles\\ForbiddenHttpException) {\n        return redirect('/')-\u003ewithErrors(['You don\\'t have the needed permissions to perform this action!']);\n    }\n    return parent::render($request, $e);\n}\n```\n\nThis way when an Forbiddeng error is thrown you'll be redirected to the given page with an error flash message. To show the message you can add the following to your blade template:\n\n```php\n@if ($errors-\u003ehas())\n\u003cdiv class=\"alert alert-danger\"\u003e\n    @foreach ($errors-\u003eall() as $error)\n        {{ $error }}\n    @endforeach\n\u003c/div\u003e\n@endif\n```\n\n### Documentation\n\nI firmly believe that even the best coded application in the world is bound to failure when missing a good documentation. That's why I humbly ask to open an issue whenever you'll think something is missing or could be improved.\n\n### Contributions\n\nI'd be glad if you'd like to contribute to the project however I'd ask not to implement new features but to improve the few existing ones (improve patterns, algorythms etc). Each PR must follow [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standards and pass all the existing tests (or add furthers when needed).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicc83%2Frooles","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicc83%2Frooles","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicc83%2Frooles/lists"}