163
Php

Laravel – 5.1 ACL Using Middleware

It’s been quite a long time I’ve written an article. Last time in 1st January 2015, I’ve written an article about ACL using Laravel-5.0 and I had to write another follow-up article but could not do it for being busy due to my freelancing job. Still now I’m occupied and busy but probably I should finish the remaining task because I’ve got some emails and comments (as requests) in my blog for the follow-up article so I’ve finally decided to write it.

The article was about Laravel-5.0 ACL Using Middleware, before the release of Laravel 5.0 official version and this is the follow-up but slightly modified and simplified, which is for Laravel-5.1.x. In this article, I’ll demonstrate the implementation of an ACL (Access Control Layer) using Laravel Middleware from the scratch. Using this ACL system anyone can develop a permission based user access control system in their application for production.

The main diffeence is that, in the old one Laravel 5.0 didn’t allow passing parameters to middleware so I’ve used a custom key in the route’s action array to mention the required permission for the route using 'permission' => 'manage_user' and it allowed to assign a single role to a user but in this one we can pass parameters to middleware so instead of using a custom key in the action array, I’ve passed the required permission as a parameter of middleware i.e: 'middleware' => 'acl:manage_user' and also I’ve allowed to assign multiple roles to any given user but one may use it for a single role based application too. So, let’s begin.

To implement this, we need 5 tables:
  • 1. users
  • 2. roles
  • 3. permissions
  • 4. permission_role (Pivot Table)
  • 5. role_user (Pivot Table)
Database migration for users table:

Database migration for roles table:

Database migration for permissions table:

Database migration for permission_role table:

Database migration for role_user table:

These tables are required to build the ACL system. The table fields could be changed (add/remove) but to build the relationship between tables we need two pivot tables and those tables should not be modified unless you know how to build many-to-many relationship between two tables using different field names than the conventional approach.

Now, we need to create the middleware class to check the user permissions and we can create it using php artisan make:middleware CheckPermission command from the command line (terminal). This will create a skeleton for a middleware class in app/Http/Middleware directory using the name CheckPermission.php. So now we need to edit that class (app/Http/Middleware/CheckPermission.php) by writing the necessary code which is given below:

Now, we need to create other classes (Eloquent Model) in app directory. So let’s create those one by one. The User.php class is available by default so you can modify that but if not present (probably deleted) then create a new one. Basically, App is used for namespacing the models and the app directory houses the classes including the default User.php but you may modify it if required, anyways, let’s create the User Model first (app/User.php):

The Role class (app/Role.php):

The Permission class (app/Permission.php):

Now, before we can use our Middleware in any route declaration, we need to add it it in the app/Http/Kernel.php file and by default, there are already other middlewares (aliases) added in that file by Laravel in the $routeMiddleware property (array) and we’ll add another one at the end of this variable which should look something like this after addition of 'acl' => \App\Http\Middleware\CheckPermission::class,:

The acl is an alias for our middleware (CheckPermission) and we’ll use the alias in our routes when declaring the routes for limited access, for example take a look at the following:

This is a route to access all users and this route is protected by the acl middleware so before the request is dispatched to the application the middleware will check if the current logged in user has the required permission which is in this case manage_user.

How it works?

Actually, this is just a demonstration of only the ACL but I didn’t provide any code which provides an user interface that let’s the admin a way to create user roles by attaching the permissions but only the core idea to implement the ACL in the application.

So, a brief idea is that, each user will be assigned one or multiple roles when user account is created from the front-end (a default role could be set from the back-end) or by the admin and the roles will be created by admin (super user) from the back-end and permissions will be attached to each roles. So, a role for example Moderator which could have a permission as Suspend User (permission title) and suspend_user (permission_slug) so we can attach suspend_user in a Route using something like this:

In this case, the route declared above requires the permission suspend_user and in the acl/CheckPermission middleware we can check the user’s permission and can protect the route if the user doesn’t has suspend_user permission. That’s it.

Note:

Notice that, this middleware also checks if the user is logged in or not so no need to use auth middleware with this and without being log in this won’t allow the use to visit any route. Also, I’ve used the Guard/Auth and didn’t use dependency injection, instead I’ve fetched the object from the service container (IoC) and it’s not a problem but you may use a constructor injection by typehinting in the __construct method of the middleware and check the old/previous article for an example of that.

Also, if you need to access any route paraneter inside the handle method then you may use somethinbg like this:

Also it’s worth remembering that, Route::parameters() method returns an array of all route parameters. For RESTful Resource controllers you may use __construct method to hook up the middleware using something like the following:

In this article, I tried discussed how to organize the tables and classes and how to filter the requests using middleware and what classes could be required but not full implementation of a fully functional system, it just gives an abstract idea to create an ACL functionality using Laravel - 5.1.x Middleware from the scratch (without using any third party package).

P/S: Some text are copied from old article so pardon me for any kind of silly mistakes. Also apologies for taking the time for writing this article even I was commited to write it months ago. Hope you would like it and your feedback is always appriciated. Thanks!

  • Mehran Hadidi

    thank Sheikh for really fast answer to requests. wow. i wondered how fast u did it :D. & it was really helpful. i Will test this code in my project. it should work. Best regards

  • I have added some modifications:

    Added

    public function isAdmin()

    {

    foreach ($this->roles as $role) {

    if ($role->role_slug == ‘admin’) return true;

    }

    return false;

    }

    to User.php

    and modified can method:

    public function can($permission = null)

    {

    return (!is_null($permission) && $this->checkPermission($permission) || $this->isAdmin());

    }

    If auth user has admin in roles he will override any permission.

    • Josué Camelo dos Santos

      Where in you have added these adaptations?

    • Thanks @sineld:disqus, this is good and I omitted it intentionally because I wanted to make it completely permissions based instead of a role based but I used is() for this kind of checking in my development for checking any role.

    • Yusuf Yılmaz

      Hi Sinan Thanks for sharing the modifications. I have a question. Why am I getting “FatalErrorException in MySqlGrammar.php line 139:

      Maximum function nesting level of ‘100’ reached, aborting!” this error on most of the pages when I use auth()->user()->isAdmin(). That doesnt make any sense and I couldnot figure out what the problem is.

  • Josué Camelo dos Santos

    I will test these tricks now. The first article is perfect. Recently I am begining the construct of a structure for my applications using Laravel 5.1. I am abandoned cakephp framework for several reasons. Soon I will write the feedback.

  • Josué Camelo dos Santos

    How to pass the parameter $permission for Middleware CheckPermission in public function handle($request, Closure $next, $permission = null)?

    I am unable to validate the access permission for my users.

    • Hi @josucamelodossantos:disqus, You can pass the parameter to the handle method using the following:

      // In the route declaration
      ‘middleware’ => [‘acl:permission_goes_here’]

      It’s given in the code example.

      • In this case:

        $router->group([‘prefix’ => ‘usuarios’, ‘middleware’ => [‘auth’, ‘acl’]], function() use ($router)
        {
        // ….
        });

        Just use the acl middleware in the specific route declaration, like:

        $router->group([‘prefix’ => ‘usuarios’, ‘middleware’ => [‘auth’]],
        function() use ($router)
        {
        $router->get(‘url_goes_here’, [‘middleware’ => ‘acl:param’, ‘uses’ => ‘SomeController@methodName’]);
        });

        • Josué Camelo dos Santos

          Thank you very much for your help , I managed to implement correctly now .

          • Glad to know that @josucamelodossantos:disqus 🙂

  • Pezhman

    getAllPernissionsFormAllRoles dosn’t work !

    would u check please 😉

    • It works, tested, what error message you got?

      • username666

        Bad method call exception: Method fetch does not exist.
        it looks like something wrong with that method “fetch”

        • Maybe you are using a different version than this, please check it.

          • He is probably using laravel 5.2, I got the same error message.

  • Chandra Shekhar

    how to check either user is admin or not?

    • Actually there is no way to do that because this is not role based instead it’s permission based, so you may check if the User has that permission using if($user->can('permission_slug')) or you may create your own function for checking if the user is admin or not.

      • Chandra Shekhar

        I have “role” field in users table,
        I want to check either user is admin or not?
        The code I have, in controller
        public function __construct()
        {
        $this->middleware(‘auth’);
        }

  • Smith Foto

    How to check permission backend navigation?

    • Use if(User::can('permission_name_or_slug')) { // ... }.

      • Smith Foto

        Thanks, now i can continue my project …

  • Smith Foto

    Do you have an example of using this method

    public function __construct()
    {
    $this->middleware(‘acl’); // To all methods

    $this->middleware(‘acl’, [‘only’ => [‘create’, ‘update’]]); // Only specified methods

    $this->middleware(‘acl’, [‘except’ => [‘index’, ‘show’]]); // All but specified ones
    }

  • Nick Smyrnaios

    Hello Sheikh Heera. Thank you for your post. It was very useful for my project.

    In case someone (like me) wants to make a relationship one-to-many between Users and Roles can change a little bit of the code in User Model for retrieving all permissions by using Eloquent. I think this is more simple and more equivalent to laravel coding. In my case is working.


    public function can($permission = null){
    return $this->checkIfHavePermission($permission);
    }

    private function checkIfHavePermission($permission = null){
    $havePermission = $this->roles->first()->permissions->where('slug', $permission);

    return !$havePermission->isEmpty();
    }

    • Thanks @nicsmyrn:disqus for your contribution, Yes should work and it works even for a single role base without changing the code but it’s better that you’ve used modified it for your own need.

  • Dimi

    Hello,
    I’m really new in Laravel but i try to use it to build a rest
    API. I feel noob and my question is surelly a basic but after following
    your tuto, i don’t know how to add user and how to log in with them. It
    seems not a problem for everybody so i think i missed something big
    about that.

    Can someone give me a small help or informations about thoses points?

    Regards and thank you for the tuto

    • Hi @disqus_QCpggtvgXS:disqus, The articles described everything from top to bottom for adding the Middleware as ACL. So you may able to use it in your project if you read the articles (5.0 and 5.1) properly. So give it a try and if you stuck at any point then please ask me specifing the exact problem you face. All the best 🙂

  • Yusuf Yılmaz

    I have seen minor thing in middleware that is redirect is not working when user not logged in. I think we should put this line after the if? return $request->ajax ? response(‘Unauthorized.’, 401) : redirect(‘/login’);

    • Thanks @disqus_fcnh886n18:disqus, Actually this middleware only for logged in users and in this case we need to use return $next($request); after the parent if condition.

      • Yusuf Yılmaz

        Thanks for the quick reply Sheikh Heera You are right this is for logged in users. However, when guest is accessing any acl restricted route, they will face with a blank page. In your redirect, user will be redirected to login page when the user does not have the permission but is logged in. So I have adjusted your middleware to my conditions and redirect the user without permssion to another route that is unauthorized page. My code sample is as

        if (!app(‘IlluminateContractsAuthGuard’)->guest()) {
        if ($request->user()->can($permission)) {
        return $next($request);
        }
        return $request->ajax ? response(‘Unauthorized.’, 401) : redirect(‘/unauthorized’);
        }
        return $request->ajax ? response(‘Unauthorized.’, 401) : redirect(‘/login’);

  • Nice work. Would love to see a follow-up article showing view implementation for ACL. I’ve noticed on Laracasts, Laravel.io and a few other sites that people are crying out for such functionality tutorials…

    • @mattbing:disqus Thanks 🙂 Hope you enjoyed the read.

  • Siddhesh

    I have implemented the all given things but want to know which values are to be inserted into database. If i comment this line ‘middleware’ => ‘acl:manage_user’, the view is shown to me. but i want to know how to use that ‘acl:manage_user’. and give permission to user for specific route?

    • manage_user in this example. All the examples with migration is provided in the article.

  • Hi,

    Thank you for sharing this nice tutorial. By the way there is one thing that i dont understand.

    In the User model, you have
    /**
    * Many-To-Many Relationship Method for accessing the User->roles
    *
    * @return QueryBuilder Object
    */
    public function roles()
    {
    return $this->belongsToMany(‘AppModelsRole’);
    }

    In the Role model:

    /**
    * users() one-to-many relationship method
    *
    * @return QueryBuilder
    */
    public function users()
    {
    return $this->hasMany(‘AppModelsUser’);
    }

    And also create an pivot table: role_user:

    Schema::create(‘roles_users’, function (Blueprint $table) {
    $table->increments(‘id’);
    $table->integer(‘role_id’);
    $table->integer(‘user_id’);
    });

    Logically, we should use the relation ” belongsToMany ” in the Role, model.

    So could you please explain.

    Thank you

    • Actually it’s

      * many-to-many relationship method.
      *
      * @return QueryBuilder
      */

      public function users()
      {
      return $this->belongsToMany(‘AppUser’);
      }

      You’ve made a mistake, that was in older version for v-5.0 where I used one role per user. Thanks for you contribution 🙂

      • tuan anh vu

        Ah i see, my mistake. Thank you 😉

  • Rodrigo Motta

    Hello everyone, someone has available the forms for User registration and login to these wonderful features? Sheikh thank you for your post, I managed to create the tables and files, now I preicsar create users and the login screen.

  • How do you detach user from specific permission.

    • By removing a permission from the group the user is assigned. Also, you are able to remove the usewr from that entire group.

  • Giorgos Karanikas

    Excellent Tutorial! How i can check user permission or role into blade.php ?

    • You may use @if(Auth::user()->can('permission_slug')).

  • cloud4bpm

    Hi @sheikh_heera, thanks for that article. One question, where is the permission parameter of the route() action? In the 5.0 version of the article was used, but on this version it doesn’t. Is that parameter used by the middleware? Thanks.

    • In 5.0 there was no way to pass parameter to the middleware so it was passed using an extrta key in the route action but since 5.1 allowes us to pass extra parameters to the middleware so I’ve used that way, for example: 'middleware' => 'acl:suspend_user'. Here, suspend_user will be available in the handle method of your middleware but in this case your method signature should be something like this public function handle($request, Closure $next, $permission = null). Hope I made it clear now.

      • cloud4bpm

        Very clear 🙂 thanks so much!

  • Giorgos Karanikas

    I have added a function in order to check user role:

    We can check via: Auth::user()->isrole(‘role_slug’);

    Functions: (in User Model):

    public function isrole($userrole = null){

    return !is_null($userrole) && $this->checkUserRole($userrole);

    }

    /**
    * Check if User Role match the given role_slug…
    *
    * @param String role slug of a role
    * @return Boolean true if role exists, otherwise false
    */
    protected function checkUserRole($givenrole){
    $getrole= $this->roles->toArray();
    foreach ($getrole as $key){
    if(array_key_exists(‘role_slug’,$key) && $key[‘role_slug’] == $givenrole){
    return true;
    }
    }
    return false;
    }

    • krishna

      hi Giorgos Karanikas ,

      i added the methods to check the user role . Now i want to redirect to admin dashboard if the the logged in user role is Admin and redirect to User Dashboard if the logged in user role is User. Where and how to write this code

      • Giorgos Karanikas

        Hi krishna!
        You should check user role of authenticated user on authenticated() function on AuthController….

        example:

        protected function authenticated(){
        if(Auth::user()->isrole(‘admin’)){
        return redirect()->intended(‘/api/v1/admin/’);
        }
        if(Auth::user()->isrole(‘customer’)){
        return redirect()->intended(‘/api/v1/customer/’);
        }
        //else….
        return redirect()->intended(‘/api/v1/’);
        }

        • krishna

          Thank you . It worked!!!

          I have a question

          1. i used make:auth for authentication.

          2. then i created
          a) users [how to write relation Primary Key. Email id is Primary Key]
          b) roles [how to write relation Primary Key. RoleId is Primary Key]
          c) permissions[how to write relation Primary Key. Permission id is Primary Key]
          d) permission_role (Pivot Table) [how to write FOREIGN Key RelationShip]
          e) role_user (Pivot Table)[how to write FOREIGN Key RelationShip]

          3. while user registration i want to give a default role. say USER_ROLE
          or during registration based upon the user selection of ROLE ,i want
          to assign the ROLE.

          How should i go with this.

          Thanks in Advance

        • krishna

          i want to display a link in my home page after login based upon the permission the logged in user have

          so in the view how i have to write the code

          regards,

          krishna

  • Nice to see the Laravel has ACL. Thanks for the article – I’ll give it a try soon.

  • is this compatible with mr jeffrey’s way?

    • No, this was made before Laravel’s ACL and it has different mechanism 🙂

    • would you like to make for the latest version. I just couldn’t find how to get the role & permission to work

  • Leon

    Hi Sheikh, nice demo! its ALMOST working for me 😉 There is one problem: in the case that a user IS logged in but DOESN’T have permission, I’m getting a blank page, as with Yusuf below…. I have called the middleware from my controller:

    public function __construct()
    {
    $this->middleware(‘acl:canviewpage’);
    }

    but it is not redirecting me back to my unauthorized route. Any idea why the blank page? Thanks

    • Hi Leon, Sorry but I can’t what is going on there in your code but all I can guess that, there is a state that doesn’t match any criterion so nothing is being returned so you get a blank page. Probably you can try this handle method instead:

      public function handle($request, Closure $next, $permission = null)
      {
      if (!app(‘IlluminateContractsAuthGuard’)->guest()) {

      if ($request->user()->can($permission)) {

      return $next($request);
      }

      return $request->ajax ? response(‘Unauthorized.’, 401) : redirect(‘/login’);
      }

      // Make sure you have a route with name “dashboard” or use something else
      return redirect()->route(‘dashboard’);
      }

      • Leon

        Ah, thats got it! Thanks for the super quick reply! Here is the handler function i ended up with:

        public function handle($request, Closure $next, $permission = null)
        {
        if(auth()->guest()) {
        return redirect()->route(‘login’);
        }

        if ($request->user()->can($permission)) {
        return $next($request);
        }

        $request->session()->flash(‘message’, ‘Sorry! You are not authorized to access that page’);
        return redirect()->route(‘home’);
        }

        And of course the routes had to be named, such as:

        Route::get(‘home’, [
        ‘as’ => ‘home’,
        ‘uses’ =>’PagesController@home’
        ]);

        Route::get(‘auth/login’, [
        ‘as’ => ‘login’,
        ‘uses’ =>’AuthAuthController@getLogin’
        ]);

        You are a star! Thanks so much for helping me out!

        • Hi @@disqus_hOY80cU4IT:disqus , Did you try the updated code?

          • Leon

            I did. It was working fine in local, so I deployed to my test environment, and got another error!! It sssem to have a problem with “can()”… I have no idea why that might be. As i said, it works on my local environment. I tried updating composer but that didn’t help. The error is:

            BadMethodCallException in Builder.php line 2025:
            Call to undefined method IlluminateDatabaseQueryBuilder::can()

            which seems to be triggered by CheckPermission.php. Any ideas?

          • @disqus_hOY80cU4IT:disqus ,Not sure, indeed (:

  • satish upadhyay

    Hi,

    I am getting following error. can you help ??

    Declaration of AppModelUser::can() must be compatible with IlluminateContractsAuthAccessAuthorizable::can($ability, $arguments = Array)

    • Yes, you are probably using Laravel’s Authorise and that contains can() method so if you want to use this implementation then you need to change the can method in User model (in a trait in my example).

      • Derick Tan

        Hi, i got the same error too, what do you mean with “change the can method in Usermodel (in a trait in my example).” . Where can I find them?

        • maanshu

          Here is the correct version of that argument.

          public function can($ability, $arguments = [])
          {
          return !is_null($ability) && $this->checkPermission($ability);
          }

  • Pankaj Sood

    Hi Heera.IT,

    Great article… I am stuck at login user. I am facing
    “NotFoundHttpException in RouteCollection.php line 161:”

    My route.php contains
    Route::get(‘login’, ‘AuthAuthController@getLogin’);
    Route::post(‘login’, ‘AuthAuthController@postLogin’);

    Route::group([‘prefix’ => ‘admin’, ‘middleware’ => ‘acl:admin’, ‘namespace’ => ‘Admin’, ‘before’ => ‘admin’], function() {
    Route::get(‘dashboard’, ‘DashboardController@index’);
    });

  • akai

    Hi heera.
    Great tut.when i run your tut,i get error “fatalErrorException in Model.php line 986” class ‘AppRole’ not found. Please help me to explain.thanks

    • Hi, Make sure you have AppRole.php file in “App” folder and the namespace is correct.

  • Anaa Raj

    I wanted to know that how to access my crud operation that should be perform by only admin or if any user is provided role of admin. And new user after login can see only some page but cant edit, delete or add. How to assign such permission and role to the admin and user. Please explain me in brief as i am new in laravel and its a assignment for me.

    • Welcome @A@anaaraj:disqus 🙂
      Anyways, what is the problem you are facing here. Basically, in your route declaration for protected routes (that requires a permission) you need to add the acl middleware and pass a parameter as the permission for that route. Hence you have to assign the permission to that role (Admin). That’s it. Hope that helps.

  • Raj Masud Forhad

    Hi heera, great tutorial. Do you have any github for this tutorial?

  • Vishal Patel

    Hello I want to pass multiple Permissions from controller to middleware like array of permission.

    like

    public function __construct(){

    $this->middleware(‘acl:user-add,usr-del,user-add’);
    }

    i wan to pass array of permission to checkpermission.php middleware.How can i?
    Thanks in advance.

  • Onur

    Thanks,

    I would like to clarify something. In case, I used RESTful Resource controller and declared middleware within _construct, how do I pass the permission parameter?

    • $this->middleware('acl:permission_name', ['only' => ['store']]);

  • khudadad

    Hi, in my case I have 3 types of users: admin, teacher and student, that a user just has only one role and a role belongs to many users, so I have created the tables with their relations but don’t know how to access and check the user roles.
    any help
    thanks

  • Uuganbayar Chuluunbaatar

    hi when i try check permission like this

    @if(Auth::user()->doIT(‘admin’))

    give this error

    Call to a member function doIT() on a non-object

    and i change function ‘can’ to ‘doIT’
    plz help

    • Make sure you are logged in.

      • Uuganbayar Chuluunbaatar

        its working fine when i’m logged in but after logout i cant login back and give me a error “Call to a member function doIT() on a non-object” and i check a role at master page

        • That won’t work if not logged in and probably u need to check if logged in first.

  • Derick Tan

    Hi, it would be great if you create a sample for this middleware :). I’m a newbie and i need a sample for me to understand the whole code

    • I’ll catch u later. Provide u some samples.

      • Derick Tan

        nice!, simple crud would make it even better 🙂

  • Dave Jong A Lock

    Is it to much to ask to add a sample UserController.php

    • Not really but my wedding is on 26th of November 2015 so you probably understood why it’s hard for me now 🙂

      • Dave Jong A Lock

        Thanks for answering! I’m wishing a lot of hapiness for both of you!

        • Thanks dear @D@davejongalock:disqus 🙂

          • Dave Jong A Lock

            Hi Sheikh,

            How’s married life? I bet it’s great!

            I need some help with a route, resourcefull. How do I add the middleware to use this Route::resource(‘clients’, ‘ClientController’); ?

          • Hi Dave,

            Thanks for asking, yes, the married life is great, anyways. You may use/create a constructo method in your Controller to add middleware calls, for example:


            public function __construct()
            {
            $this->middleware('auth');
            // Or
            $this->middleware('auth', ['only' => [
            'updateMethod',
            'DeleteMethod',
            ]]);
            }

            Hope it helps. More on: https://laravel.com/docs/master/controllers#controller-middleware 🙂

  • tanveer ahmad

    here you are giving permission to the roles. if we assign some permission to a role it is given to all the users associated with the role. what if we want to take away a permission from a single user. or we give a special permission to a user

    • Broad question, it depends, could be so many ways 🙂

  • Harry Bosh

    Hey Mate, Thanks for this!

    Is this going to impact with socialite? Because i am having trouble implementing socialite into my laravel 5.2

    • You are welcome 🙂 Probably not but not sure yet.

  • Thiago Antonius

    Nice tutorial. * array_fetch is deprecated. In Laravel 5.1 is array_pluck.

  • OjciecNarodu

    how about laravels 5.1 Gate authorization?

  • Jax Reynolds

    This is a great tutorial, but I have a question about user roles. I have 3 types of users, admin, candidate and company. How do they choose their roles? I do not want the admin to choose it, I want them to be able to choose it when they register. So when the user registers and they hit submit it takes them to the page they are allowed to go to. Any help with this.

    • You have to add a select/dropdown containing rules (id as value and title as text) then you may validate if the user selected a role when they submits the form. When showing the registration form, also pass the roles array to populate the dropdown. It’s very simple. Btw, I’m assigning a default role in this example so no need to pass the roles since I’m taking the control here. Hope it helps 🙂

      • Jax Reynolds

        Thank you, I am so new to this it is quite overwhelming. For me seeing examples helps understanding it. Do you know where I can see an example of what you are telling me?

  • Kris Trawa

    Any suggestions how to implement super user, which will omit checking of any priviliges?

    • Create a function/method isSuperUser() and use that function inside the can() method at first. Return true from the can() method if

      if($this->isSuperUser()) {
      return true; //first line
      }
      // Rest of the code
      .

  • Kris Trawa

    In my routes I have registered a resourceful route to controller like that:
    Route::resource(‘user’, ‘UserController’);
    Then I wanted to use acl for all methods of my controller so I added this:
    $this->middleware(‘acl’); to its constructor. What should be the slugs defined in db for permissions to basic routes like ‘user’, ‘user.create’ and so on?

    • Use create_user and so as slug.

      • Kris Trawa

        Unfortunately it doesn’t work. Eg route /user/create/ works fine if it is defined in routes like that

        Route::get(‘user/create’, [
        ‘middleware’ => ‘acl:create_user’,
        ‘uses’ => ‘UserController@create’
        ]);

        But it does not work when defined as I described earlier. Would be great if it could working, it would be nice usage of Laravel feature of resoureceful route defining.

  • JohanVick

    Hi i want to assign roles and permissions using tinker so i write the following

    Role.php

    public function assign(Permission $permission){

    return $this->permissions()->save($permission);

    }

    User.php

    public function assign($role){

    if (is_string($role)) {

    return $this->roles()->save(

    Role::whereName($role)->firstOrFail()

    );

    }

    return $this->roles()->save($role);

    }

    But i try
    $adminRole=new Role
    $permission=new Permission
    Role and permission are already store in DB using Tinker
    $adminRole->assign($permission) it give undefined error I dont understand why

  • Pionas

    Hi,

    i don’t understand everything.
    Why you add role_slug?
    i can’t find where you use it…
    In Middleware i can add only permission_slug.
    Firstly i find all roles assigned to user, and next find all permissions assigned to roles.
    Can you add example how to add roles/permissions when user register?

    • Pionas

      Sorry, my mistake
      I turned the importance of permissions and roles 😉

  • Adrian

    Can you add some sample how create user account and add default roles and permissions and how added new role/permission?

    • Shamir Husein

      Me to, i need the table seeder 😀
      hehehe
      thanks

      • Seeders are already added with example code here 🙂

        • Shamir Husein

          sorry sir, I do not find the seeder .
          hehehehe
          can u give me the link or where I can find it ?

          • Sorry, no seeders are given but migrations 🙂

      • Pionas

        My example:
        /* RolesSeeder */
        DB::table(‘roles’)->insert([
        ‘id’ => 1,
        ‘role_title’ => ‘Manage users’,
        ‘role_slug’ => ‘users_manage’,
        ]);

        /* PermissionsSeeder */

        DB::table(‘permissions’)->insert([
        ‘id’ => 1,
        ‘permission_title’ => ‘Users add’,
        ‘permission_slug’ => ‘user_add’,
        ‘permission_description’ => NULL,
        ]);

        DB::table(‘permissions’)->insert([
        ‘id’ => 2,
        ‘permission_title’ => ‘Users edit’,
        ‘permission_slug’ => ‘user_edit’,
        ‘permission_description’ => NULL,
        ]);

        DB::table(‘permissions’)->insert([
        ‘id’ => 3,
        ‘permission_title’ => ‘Users delete’,
        ‘permission_slug’ => ‘user_delete’,
        ‘permission_description’ => NULL,
        ]);

        /* PermissionRoleSeeder */
        DB::table(‘permission_role’)->insert([
        ‘permission_id’ => 1,
        ‘role_id’ => 1,
        ]);
        DB::table(‘permission_role’)->insert([
        ‘permission_id’ => 2,
        ‘role_id’ => 1,
        ]);
        DB::table(‘permission_role’)->insert([
        ‘permission_id’ => 3,
        ‘role_id’ => 1,
        ]);

        /* RoleUserSeeder */
        DB::table(‘role_user’)->insert([
        ‘id’ => NULL,
        ‘role_id’ => 1,
        ‘user_id’ => 1, // user_id must be in a table of users
        ]);

        You can add above code to /database/seeds/DatabaseSeeder.php
        or create all files and in DatabaseSeeder add e.g. $this->call(RoleUserSeeder::class);

        /* some controller */
        public function __construct()
        {
        $this->middleware(‘acl:article_add’, [‘only’ => [‘create’, ‘insert’]]);
        $this->middleware(‘acl:article_edit’, [‘only’ => [‘edit’, ‘update’]]);
        $this->middleware(‘acl:article_delete’, [‘only’ => [‘delete’]]);
        }

  • ape

    Thanks for your post, but your permission check is very wrong! It fails if a route requires multiple permissions.

    This line fails:
    return count(array_intersect($permissions, $permissionArray));

    Say if I have the permissions $permissions = [1] and the permissions required are $permissionArray = [1,2], array_intersect will return [1] (read the phpdoc). Then the count function will return 1, that leads to:

    count(array_intersect([1], [1,2]) == true

    What you really need is something like this:

    // the sequence of the parameters here is VERY important!
    return array_diff($requiredPermissions, $userPermissions) === []

    • I’ll check later, thanks for your input tho 🙂

  • Divo

    Thanks for this awesome tutorial. I wish I saw it earlier. Here is how I have been going, hope I have not been completely off track: I have a users table with boolean columns: is_supervisor, is_admin, is_manager, is_super_admin indicating the different kinds of users (a user can have just one role). Then I have middlewares such as RedirectIfNotManager, RedirectIfNotAdmin, RedirectIfNotSupervisor, etc. On a typical controller constructor I have something like below:

    $this->middleware(‘manager’, [‘only’ => array(‘index’, ‘view_all’, ‘edit_all’)]);

    Now in a situation where only a manager or a supervisor should have access to a given method in a controller, do I need to create another middleware say RedirectIfNotManagerOrSupervisor and call it in the constructor like below:

    $this->middleware(‘manager_or_supervisor’, [‘only’ => array( ‘show’)])

    Here is my use case, in a given controller, they’re certain methods that if you not a supervisor or manager, then you should be redirected while for some other methods in thesame controller, if you are not an admin then you should be redirected. How do you suggest I approach this? thanks

    • Your’s is a little bit different so probably you can try what you are asking for 🙂

      • Divo

        Thank you so much for the reply. I am going to try it and see what I get. Laravel rocks 🙂

    • krishna

      Hi Divo,
      how can i create a profile for a user. when registering a user i want create a profile which will be in a table ‘profiles’. A user wil have one profile.
      i am using make:auth package and along with that i want to user Shaiks ACL .

      • Divo

        Hello Krishna, actually I build mine from scratch. I have never used an existing package. The users table contain the profile details. If there are different kinds of users with different kinds of information, I may consider inheritance. Hope this helps.

  • krishna

    Hi Heera,

    can you please provide the relationship for tables like Primary Key and Foriegn Key

    1. users

    2. roles

    3. permissions

    4. permission_role (Pivot Table)

    5. role_user (Pivot Table)

    Regards,

    Krishna

    • Actually, users are related to roles (one user may have more than than one role) using role_user and permission_role pivot table maps which permissions belong to which roles. Hope it make sense 🙂

      • krishna

        Hi Sheikh,

        i want to display a link in my home page after login based upon the permission the logged in user have
        so in the view how i have to write the code

        regards,
        krishna

        • You may try something like this:

          @if(auth()->user()->can(‘permission_name’))
          Link Goes Here
          @endif

  • krishna

    Hi ALL,
    I had a strange problem. Following are things i did

    created laravel project and used WINDOWS IIS SERVER instead of XAMPP
    configured database mysql
    used make:auth
    clicked on register . created the user
    user created in the database user table
    but after registration it should go home page i.e. dashboard page
    instead it stay on the same page i.e. Welcome page
    but if i type localhost:81/home.. it works. i can see the Home/Dashboard page
    only after i logout i can proceed to login page or registration page.

    Can anyone help me on this.

    Regards,
    Krishna

  • Pei Dinh

    Hi all,
    I have problem when using i$request->user()->can($permission) –> error : ” Model.php line 1011:
    Class ‘AppRole’ not found”.
    Can anyone help me on this. Thanks

    • Mitchell

      If you are still looking for an answer. I fixed it by changing the namespace in both Role.php and Permission.php to just App (so not AppRole or AppPermission).

  • Ryan Zen

    Hi, First of all, thank you so much for the sample code. I am trying it our in Laravel 5.2

    However, i got error at the User.php->getAllPermissionsFormAllRoles()
    Line : $permissions = $this->roles->load(‘permissions’)->fetch(‘permissions’)->toArray();

    The error message is : Method Fetch does not exist

    #0 – in Macroable.php line 81
    #1 – at Collection->__call(‘fetch’, array(‘permissions’)) in User.php line 72
    #2 – at Collection->fetch(‘permissions’) in User.php line 72
    #3 – at User->getAllPermissionsFormAllRoles() in User.php line 55

    When i dd($this->role) , i get a collection object with Object Role and its relationship.
    Could this be because Collection object does not have fetch method anymore.

    Thank you very much for the help 🙂

    • The collection fetch method has been deprecated in favor of the pluck method.
      The array_fetch helper has been deprecated in favor of the array_pluck method.

  • John Carpenter

    Just wanted to say thanks very much for this post, it helped me greatly. Works on Laravel 5.2 after changing a couple of deprecated commands (fetch and and another one I can’t remember) and a couple of wrong namespaces.

    • Glad you made it useful for yourself and I would add a note for depricated functions 🙂

    • Ryan Zen

      Thank you very much for the prompt reply….will take note on that ….:)
      Will use array_pluck instead

  • Divo

    Hello, I thought laravel 5.1 shipped with ACL already.

  • hcamacho

    Hi Sheikh, thanks for your tutorial, i have a little error when i trying to get access in a module under ACL, the error is:

    FatalErrorException in User.php line 72

    Call to a member function load() on null

    The line 72 is: $permissions = $this->roles->load(‘permissions’)->fetch(‘permissions’)->toArray();

    Can you help me?

    • Hi @hc@hcamacho:disqus, Try to replace roles->load('...') with roles->permissions.

      • hcamacho

        Thank you very much man!

  • Gastón

    Awesome! i was following your previous post “Laravel – 5.0 ACL Using Middleware” and then i saw this one, thanks so much for taking the time to update and share this!!

    • Welcome and glad to know that, it was helpful to you 🙂

  • Leon

    Hi Sheikh. When creating a user, how can I use your ACL script to set the user role at the same time? I know I need to insert a role id into the role_user table, but is there a command for doing this? Thanks.

    • You can just add the role (id/slug) with the user inputs. Probably you can fetch the roles from it’s table first then integrate the appropriate role with user inputs.

  • Showket Bhat

    Hi Sheikh, I have implemented your ACL Layer in my application, and it works like a charm, only issue is i want to allow all users to access (say edit) their own records. Lets say a user can see all users but can edit only his own Info. I have created a permission edit_user if i give this permission to a user he has full rights to change any user details. How can i achieve what i want. thanks in advance

  • lemon

    Hi Sheikh, first thanks for the awesome tutorial.

    However, if i want to try adding role or persmission from the backend (like you said in ‘how it works?’ part)
    What should i do in middleware parameter in route file ? How to set the role and permission dynamically by getting data from backend ?

    Route::get(‘/users’, [
    ‘middleware’ => ‘acl:manage_user’, // what should i write here ?
    ‘as’ => ‘users.all’,
    ‘uses’ => ‘UserController@index’
    ]);

    Thanks

    • Welcome. You should write the permission_slug there.

      • lemon

        Thanks Sheikh,

        Now if i want to have a route that can access by all user (so i plan not to attach middleware acl), for example
        Route::get(‘/users’, [
        ‘as’ => ‘users.all’,
        ‘uses’ => ‘UserController@index’
        ]);

        After a while i want to update that route is only can access by admin, the update done from the backend.
        What should i do ? should i attach middleware acl to all route from the start ?

    • lemon

      Thanks Sheikh,

      Now if i want to have a route that can access by all user (so i plan not to attach middleware acl), for example
      Route::get(‘/users’, [
      ‘as’ => ‘users.all’,
      ‘uses’ => ‘UserController@index’
      ]);

      After a while i want to update that route is only can access by admin, the update done from the backend.
      What should i do ? should i attach middleware acl to all route from the start ?

  • Jaidul Islam

    It’s really awesome my mentor, I will keep reading your all post. The main advantage is, you have been writing the whole article with simple sentences which is really readable and understandable.

    Thanks Guru.

    • Welcome and glad to know that, you liked it 🙂

  • Flor

    HI! I had a problem when I installed acl.. the session token of laravel changes after a time (random) and I can´t find why. Do you have any idea about it?

  • Arun Nair

    Hi Heera,
    I have a problem with laravel5.4
    I use middleware is public function handle($request, Closure $next, $permission = null)
    {
    if ( !empty( auth()->guard(‘user’)->id() ) ) {

    // dd( $request );
    if ( auth()->user()->can(‘permission_name’) ) {

    return $next($request);
    }
    }

    return $request->ajax ? response(‘Unauthorized.’, 401) : redirect(‘/login’);
    }

    Error comes
    ” (1/1) FatalErrorException

    Call to a member function can() on null ”

    Another way
    public function handle($request, Closure $next, $permission = null)
    {
    if( !empty( auth()->guard(‘user’)->id() ) )
    {
    // dd( $request );
    if ($request->user()->can($permission)) {

    return $next($request);
    }
    }

    return $request->ajax ? response(‘Unauthorized.’, 401) : redirect(‘/login’);
    }
    Same error come.

    • It’s obvious that, the user is null so user is not logged in. You probably need to check your route for auth middleware.

  • Girjesh Upadhayay

    Declaration of AppUser::can($permission = NULL) must be compatible with IlluminateContractsAuthAccessAuthorizable::can($ability, $arguments = Array)
    I am getting error

    • Rename the can method using hasPermission inside User and also change the can in middleware. Laravel uses a can method now.

  • Yulianto Saparudin Bahtiar

    How to place a permission in construct but handle in every function,
    user_add => function create
    user_edit => function update
    user_save => function store
    user_update => function update

    should I place middleware in every function not in construct? Please help me, I don’t know what should I do? I want to make a dynamically.
    I’m sorry for bad English

    • This is designed to protect routes so you have to place permissions in route.

Latest Blog