Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jasonwilson's avatar

Roles Permissions - AuthServiceProvider - Auth User Null

Greetings

In regards to Roles and Permission - just wondering what people are doing with multiple permission tables when they setup the 'AuthServiceProvider.php' file...

For example, I am using this below code for a single permission table, which works great!... However, as the application grows into difference directions - I believe a 2nd Roles / Permission table would be nice to implement...

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use App\Models\RBAC\Permission;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider {
  /**
   * The policy mappings for the application.
   *
   * @var array
   */
  protected $policies = [
    'App\Model' => 'App\Policies\ModelPolicy',
  ];


  /**
   * Register any authentication / authorization services.
   *
   * @return void
   */
  public function boot() {
    $this->registerPolicies();

      //Fetch all Permissions from the database...
      foreach ($this->getPermissions() as $permission) {

        //With each permission - register it with the 'Gate' class...
        Gate::define($permission->section . '_' . $permission->access_type, function ($user) use ($permission) {

          //Return true if the User has the given role...
          //(i.e. Does the User have any of the roles, which are associated
          //to this given permissions)
          return $user->hasRole($permission->roles);

        });
     }
  }

I thought a quick and easy way to control which permissions would be relevant to the user would be to use something like getting the authenticated user, whereby the 'guard' parameter could control which permissions are relevant... However, this didn't go to plan, as the 'Auth::guard' return null. Below is an example of the code with 2x permissions table that I tried to use...

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Auth;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Gate;
use App\Models\RBAC\Permission_demo;
use App\Models\RBAC\Permission_admin;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider {
  /**
   * The policy mappings for the application.
   *
   * @var array
   */
  protected $policies = [
    'App\Model' => 'App\Policies\ModelPolicy',
  ];


  /**
   * Register any authentication / authorization services.
   *
   * @return void
   */
  public function boot() {
    $this->registerPolicies();

    //Set Permissions if login as DEMO...
    if (Auth::guard('demo')->check()) {

      //Fetch all Permissions from the database...
      foreach ($this->getPermissions_demo() as $permission_demo) {
        
    //With each permission - register it with the 'Gate' class...
        Gate::define($permission_demo->section . '_' . $permission_demo->access_type, function ($user) use ($permission_demo) {
          
      //Return true if the User has the given role...
          //(i.e. Does the User have any of the roles, which are associated
          //to this given permissions)
          return $user->hasRole($permission_demo->roles_demo);
        });
      }
    }


    //Set Permissions if login as ADMIN...
    if (Auth::guard('admin')->check()) {

      //Fetch all Permissions from the database...
      foreach ($this->getPermissions_admin() as $permission_admin) {
       
    //With each permission - register it with the 'Gate' class...
        Gate::define($permission_admin->section . '_' . $permission_admin->access_type, function ($user) use ($permission_admin) {
          
      //Return true if the User has the given role...
          //(i.e. Does the User have any of the roles, which are associated
          //to this given permissions)
          return $user->hasRole($permission_admin->roles_admin);
        });
      }
    }
 }

I suppose that I could revise the current permissions table (and I guess this may happen eventually)... But I thought I would reach out to the Laracast community first and see if anyone else had stumble across this issue with 'AuthServiceProvider.php'.

Thanks in advance for your time and assistance.

0 likes
3 replies
bobbybouwmann's avatar

I think your getPermissions method should be responsible for only getting the permissions of the given user.

I currently have a middleware in place which is checking if the user is allowed to enter a certain route. So the permission name is the same as the route name.

<?php

namespace App\Http\Middleware;

use Closure;

class IsAuthorized
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (hasPermission($request->route()->getName())) {
            return $next($request);
        }

        // TODO: Replace with API response
        abort(403, 'Unauthorized action.');
    }
}

The hasPermission looks like this, which is stored in a helpers.php file so I can call the method everywhere. The method is really fast because it uses caching for the permissions.

// helpers.php

function hasPermission($route)
{
    $key = 'permissions' . auth()->user()->id;

    $permissions = Cache::remember($key, config('feestgemak.cache_minutes'), function () {
        $collection = collect();

        auth()->user()->load('roles.permissions');

        foreach (auth()->user()->roles as $role) {
            foreach ($role->permissions as $permission) {
                $collection->push($permission->name);
            }
        }

        return $collection;
    });

    return $permissions->contains($route);
}

However this setup is a bit different from yours. I have roles and permissions separate. A user has one or many roles and each role has one or many permissions.

jekinney's avatar

Generally a permission is assigned to a role and a role to a user. Though not required, generally as it's cleaner then assigning a bunch of users a bunch of permissions.

I set a Role and Permission Model with a table each Then two pivot tables (if you want a possibility a a user having more then one role)

role_user permission_role


class User
{
    public function hasRole($roleSlug)
    {
        foreach($this->roles as $role)
        {
            if($role->slug == $roleSlug) {
                return true; // has role
        }
        return false; // not assigned
    }

    public function hasPermission($permisisonSlug)
    {
        foreach($this->roles()->with('permisisons')->get() as $role) {
            foreach($role->permissions as $permission) {
                if($permission->slug == $permisisonSlug) {
                    return true; // has the permission assigned
                }
            }
        }
        return false; // does not have a role with applicable permission
    }
}

Nothing wrong with your attempt persay, just backwards from the norm is all.

@bobbybouwmann is a bit different, but along the same lines as above.

I to set dynamic middlewares:

Route::middleware('permission:can_post')
// or 
Route::middleware('role:admin')

Though many times the Role isn't hardcoded, but permissions are as a role's permissions probably can change.

jasonwilson's avatar
jasonwilson
OP
Best Answer
Level 4

Thanks guys for your input - it has helped immensely!

I have reviewed my code to tried your suggestions above, which has helped me to find the errors in my code (thank you!)...

First Mistake: The 'Gate' class in 'AuthServiceProvider.php' - it needed a prefix for the constant (i.e. 'admin' for the 1st table and 'demo' for the 2nd table. This just reinforce that there is no sharing of the permission tables (which there was in my case, if both permissions table had the same values)...

    //Example of Missing Prefix for Constant... 
        Gate::define($permission_demo->section . '_' . $permission_demo->access_type,
          function ($user) use ($permission_demo)

    //Example of adding Prefix... 
        Gate::define($permission_demo->database_type . '_' .$permission_demo->section . '_' . $permission_demo->access_type,
          function ($user) use ($permission_demo)

Second Mistake: I have multiple guards in my 'auth.php' file. However, it was only the 'default' guard that was working, which I didn't realize at the time. To my understanding - you needed to specify a guard and consequently bind it to the 'auth' middleware route. In my example, I used the constructor in the controllers to achieve this...

class AdminController extends Controller {

  protected $guard = 'admin';


  /**|--------------------------------------------------------------------------
  | Administration Controller - Incorrect Setup for Multiple Guards
  |----------------------------------------------------------------------------- */

  public function __construct(){
    $this->middleware('admin');
  }


class AdminController extends Controller {

  protected $guard = 'admin';


  /**|--------------------------------------------------------------------------
  | Administration Controller - Correct Setup for Multiple Guards
  |----------------------------------------------------------------------------- */

  public function __construct(){
    $this->middleware('auth:admin');
  }

Thanks again guys for your help - it was much appreciated!

Please or to participate in this conversation.