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

mallorca's avatar

Good practice on adding simple user roles

I'm new to Laravel and I hope I can get some advices from someone with experience.

I have a user table with an additional string attribute named "role". It will only contain 3 different roles, one player, one coach and one admin.

Right now, I have edited the register form so that it accepts those 3 roles and it works fine to add the users with different role attributes.

I have created a middleware for the role handling but need some coding assistance on how to verify that the user has a specific role. The goal in this case is to make a simple route verify that the user has a specific role.

What would be a good practice to make it happen using Laravel 5.1? Also I'm wondering, would it be better if I create a separate table for the roles and add a foreign key to the user? Even if it's a simple case? Appreciate all the help I can get.

0 likes
8 replies
Mithridates's avatar

Since role and a user is a many to many relationship so to speak, I think you need to add another model and table for roles.
So that a user can have many roles and permissions associated with it. Take a look at this package

mallorca's avatar

Thank you for the reply. However, I don't want to use packages in this case since this is for educational purposes.

Let's say I create another model and table for the roles. Then what? I would need a broader explanation with code examples.

willvincent's avatar

Well.. to get that field value, when a user is logged in; Auth::user()->role should do it.

So presumably, you just need to check if that is equal to the desired value or not,

You could do something like this..

RestrictByRole.php (middleware):

<?php
namespace App\Http\Middleware;

use Closure;

class RestrictByRole
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $roles = $this->getRoles($request);
 
        if ( !in_array(Auth::user()->role, $roles) ) {
            return response('Unauthorized.', 401);
        }
 
        return $next($request);
    }
 
    /**
     * Grab the roles from the request
     *
     * @param  \Illuminate\Http\Request  $request
     * @return Array
     */
    private function getRoles($request)
    {
        $actions = $request->route()->getAction();
        return $actions['roles'];
    }
}

Assuming you add that to $routeMiddleware in app/Http/Kernel.php as role.restrict, then in your routes that you want to restrict to a particular role, or roles, define them thusly:

Route::get('players/only', ['middleware' => 'role.restrict', 'roles' => ['player'], 'uses' => 'SomeController@index']);
Route::get('coaches/only', ['middleware' => 'role.restrict', 'roles' => ['coach'], 'uses' => 'SomeOtherController@index']);
Route::get('admin-coach/only', ['middleware' => 'role.restrict', 'roles' => ['coach', 'admin'], 'uses' => 'YetAnotherController@index']);

I assume though, since you have an 'admin' role, you'd want to change the handle method to something more like this:

public function handle($request, Closure $next)
{
  $roles = $this->getRoles($request);

  $role = Auth::user()->role;
  if ($role == 'admin') {
    return $next($request);
  }
  elseif ( !in_array($role, $roles) ) {
    return response('Unauthorized.', 401);
  }
 
  return $next($request);
}

That will allow an admin to access all routes, or users with a require role to access restricted routes, and error for everyone else.

3 likes
willvincent's avatar

That's based on your very simple "user just has a string value 'role' column" in the DB.

Yes, a separate table to define roles, with a 1:many relationship (user belongsTo one role, role hasMany users) would be better.. but for your simple example, something like the above should get you there.

mallorca's avatar

Thank you willvincent for the detailed explanation! I appreciate the effort!

If I added it to a separate table, what changes would I need to make? How would I verify that it's the same role as in a separate table?

Mithridates's avatar

@bobeta that's exactly @willvincent mentioned. By adding roles to another table you will have the ability to assign various roles to a user.in your roles table:

    $table->increments('id');
      Schema::create('roles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->unique();
            $table->string('display_name')->nullable();
            $table->string('description')->nullable();
            $table->timestamps();
        });

Since it's a many to many relation you need another table concatenating different users with different roles So:

  Schema::create('role_user', function (Blueprint $table) {
            $table->integer('user_id')->unsigned();
            $table->integer('role_id')->unsigned();

            $table->foreign('user_id')->references('id')->on('users')
                ->onUpdate('cascade')->onDelete('cascade');
            $table->foreign('role_id')->references('id')->on('roles')
                ->onUpdate('cascade')->onDelete('cascade');

            $table->primary(['user_id', 'role_id']);
        });

you would also need permissions table and permission_role table to associate different roles with different permissions which I didn't mentioned.
To become more fimiliar with this type of relations take a look <a href"http://laravel.com/docs/5.1/eloquent-relationships#many-to-many">HERE
Some refactors is needed is mentioned in previous answers

mallorca's avatar

@willvincent Trying the solution you provided above, I get the following error: "ErrorException in RedirectIfNotManager.php line 39: Undefined index: roles"

Sems like it's referring to the return line in the public function getRoles. Do you know why it might be?

willvincent's avatar

@Mithridates: It would only be a many to many if users had more than one role. If users only can have a single role it would be a one to many relationship.

@bobeta Sorry.. copy/pasted someone elses code.. didn't fully change it. :)

In the routes where it says 'permissions' => [...]

that should be 'roles' => [..]

I'll update the example code.

Please or to participate in this conversation.