4

Below description is based on Laravel development.

A brief description of the functionality I am hoping to achieve is,

There are 3 types of users. Superadmin, Admin and Enduser.

Only one Superadmin exist and he can create both Admins and Endusers. There can be multiple Admins exist and an admin is defined for a given site. An admin can create multiple Endusers.

To facilitate above use case, what sort of approach should I take in Laravel?

My attempt to accomplish this so far is:

I implemented multiple guards and then I was stuck since there are some routes which should be accessible by all types of users. I couldn't get it done with multiple guards since if I define multiple guards for a route, that route is only accessible only if all the multiple user types are logged in.

Say, I have a route guarded by Superadmin and Admin, this route is not available only if I logged in as Superadmin. Route is available only if both Superadmin and Admin are logged in.

Seems if we assign multiple guards, guards are ANDed. But I need them to be ORed.

guard assignment:

Route::group(['middleware' => ['auth:superadmin', 'auth:admin']], function() {...

4 Answers 4

3

Instead of Guards, I would separate out the SuperAdmin, Admin, and EndUser into individual middleware that performs a simple role check. For example a SuperAdmin middleware:

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if (Auth::user()->isSuperAdmin) {
        return $next($request);
    }

    abort(404);
}

then regular Admin

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if (Auth::user()->isSuperAdmin || Auth::user()->isAdmin) {
        return $next($request);
    }

    abort(404);
}

and then finally a simple check for authenticated users, i.e. EndUser

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if (Auth::check()) {
        return $next($request);
    }

    abort(404);
}

Then you can apply the middle to your groups as needed.

Route::group(['middleware' => ['superadmin']], function() {...

Route::group(['middleware' => ['admin']], function() {...

Route::group(['middleware' => ['enduser']], function() {...
Sign up to request clarification or add additional context in comments.

5 Comments

I will try this and get back with the results (Y)
@LakmalPremaratne, Is the above solution method works.
@shankarmsr, I managed to get it done using authorizations. I created a middleware which will check whether a particular resource is authorized for a given user (or type of user).
@shankarmsr, Permissions (resources) are grouped into Permission Set and each user is assigned to a User Role. Then a User Role is granted to a Permission Set. I find lot of flexibility in this solution.
Read up on Authorization Policies. Using roles and permissions in conjunction with policies and middleware like I've shown above will most likely cover every security need within your application.
2

By your logic, a Superadmin is always an admin, and an Admin is also an Enduser. If you start with opening routes in nested level you can get this work like.

Route::group(['middleware' => ['auth:enduser']], function(){
    // All the routes available for Enduser


    // For Admin
    Route::group(['middleware' => ['auth:admin']], function(){
        // Give admin routes here


        //Create group for SuperAdmin
        Route::group(['middleware'=>['auth:superadmin']], function(){
              // Super admin routes
        });
    });
});

This way Superadmin had everything accessabile.

3 Comments

If I group the routes in nested form, superadmin routes are guarded by both enduder and admin. Both enduser and admin have to be logged in to access superadmin route. I tested and it redirects me to Enduser login page.
Your admin and superadmin should be enduser, this is very definition of Role Based Access.
I cannot get what you mean. Can u please direct me to some resources where it explains what you mean?
2

I managed to get it solved. No multiple guards. As @anwerj pointed out, all the users are type ENDUSER

  1. Added user_type as an attribute to User model. SUPERADMIN, ADMIN and ENDUSER are the three user types. It is different from user role since a user can take multiple roles whereas once a user designated as ADMIN, will be ADMIN forever and he can have special privileges.
  2. Implemented authorization mechanism where a route can be granted either
    • to a single user (i.e. only the granted user can have access to the particular route) or
    • to a user role (not the user_type mentioned above. A user role might have multiple users)
  3. Routes were grouped to permission_set. A user_role can have multiple permission_sets

When a user logs in, middleware checks whether the resource being requested is granted for the User.

Comments

0

You can pass multiple arguments to a piece of middleware like this.

$this->group(['middleware' => ['restricted.role:super-admin,admin']], function () {
    // ...
});

The RestrictedRole middleware class handle method will look like this.

public function handle($request, Closure $next, ...$roles)
{
    if (Auth::user()->inRoles($roles)) {
        return response()->json(['error' => "You don't have access to that"], 401);
    }
    return $next($request);
}

Finally, the User class will implement an inRole method like this.

public function inRoles($roles)
{
    return in_array($this->getAttribute('role'), $roles);
}

You can also nest routes and restrict roles further like this.

$this->group(['middleware' => ['restricted.role:super-admin,admin']], function () {
    // super-admin and admin can access this block of routes.

    $this->group(['middleware' => ['restricted.role:super-admin']], function () {
        // Only super-admin can access this block of routes.
    });
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.