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

richiesh's avatar

Laravel Roles

Hello,

I've been working on a small project and looking to make some changes to make it easier to manage. I have Roles setup which allow me to determine what people can see and do. I have a set of webpages which the source for each page is stored in the database. I have a controller which handles this so /page/1 would request the table row with ID 1, and so on.

At the moment, I'm having to hard code the following -

if (Auth::user()->hasAnyRole(['Group1','Group2'])) { }

In many of my views, etc. I'm looking to add a new column to my "pages" table called "permissions", which would hold the value of say 'Group1','Group2' as a string for in my example, row #1. I've done that, but I'm struggling to pull this value from the DB into my if statement. I even tried doing this at the view level with the following -

@if(Auth::user()->hasAnyRole([{{!! $page->permissions !!}}]))

Test

@endif

But this didn't work either.

I'm pretty new to this so apologies if I haven't explained this too well!

Appreciate any help/advice you can give :)

0 likes
11 replies
jlrdw's avatar

I look at it in stages, example:

Route::get('indexadmin', 'DogController@indexAdmin')->middleware('auth');

But I usually use route groups.

All that does is tell me someone has to be logged in to use that method, but who.

I have roles like:


   roles 
-------------
admin
bkeep  // for bookkeeper
admin,bkeep   // both roles
user
etc

On a method I verify if the required role matches the current logged in users role.

Which for admin, bookkeeper, that is enough.

However for a user who can edit their own data only, you also need a check to ensure the id of the logged in user matches the forign key id on the data in question. Something like:

if ($request->id === Auth::id()) {
  return $next($request);
}

And an example of a non-laravel framework, just an example only:

// an edit example
$data['row'] = $this->Pet->getPet($petid);
Cln::chkUserId($data['row']->owner_id);

And it calls a check:

    public static function chkUserId($userid)
    {
        if ($userid === Session::get('owner') || Session::get('isadmin') === 'admin') {
            return;
        }
   return false;
   {

You need a check of the proper id, otherwise someone could just put an id in the url, and that record would come up for an edit.

To me roles make sense, but permissions can be done in the controller and models via the correct role and correct id.

Permissions can also be redundant, Meaning as example, take the bookkeeper, of course they can view, edit, add, or whatever to bookkeeping. So if the role is bookkeeper matches, all is okay.

Permissions can allow a non bookkeeper in there, but perhaps they can only view the data.

Permissions require a lot of extra if statements, "can", "cannot", etc. Which is fine for some.

But add up the lines of code that the extra checks, "if", "can", "cannot", etc places in the code.

To me it's easier to just write an extra method for someone who can only view bookkeeping, if the role matches, all is done. None of the extra checks required.

I have seen some of the examples, and in a large system there is no telling how many "can", "cannots" are needed.

An extra method and view fulfills the same thing. As long as the persons role matches the required role for the controller method.

Of course do the permissions as you see fit.

But there are several ways of using an RBAC system. There are ways to keep it simple yet secure.

rawilk's avatar

Try writing your conditional like this instead:

@if(auth()->user()->hasAnyRole($page->permissions))
Test
@endif

You don't need the {!! when you're in a blade directive.

1 like
richiesh's avatar

@WILK_RANDALL - Thank you for your response. I did try this but it wasn't displaying anything inside the if statement, tried again and it's still doing the same thing... confused! Basically, there is a permissions column added to the page table. In that column for each page as a test, I've got 'Group1','Group2','Group3','Group4'. It doesn't look like those values are being pulled from the DB when using that method.

I can pull the values from the DB if I simply place {{!! $page->permissions !!}} in the blade, this displays the value of that column when you load the page... so it is in a way managing to pull the values.

richiesh's avatar

@JLRDW - Thank you for your very detailed response. I'll need to take some time to look at this fully.

rawilk's avatar

@richiesh It's hard to say why it's not showing up for you. It appears you're using https://github.com/spatie/laravel-permission but I could be wrong. If so, I think if you want to check for multiple roles in that method, you need to pass it an array, but from what you've shown it looks like you have a string of all the group names, so the method is thinking you're only checking for one and and that the role's name is Group1,Group2,Group3,Group4.

If that's the case, it looks like you would just need to convert that string to an array and then pass that into the hasAnyRole function.

@if (auth()->user()->hasAnyRole(explode(',', $page->permissions))
     Test
@endif
1 like
jlrdw's avatar

I do something like:

    public static function verifyRole($role = null, $userrole = null)
    {
        $checkrole = explode(',', $userrole);
        $match = in_array($role, $checkrole) ? 'is_matched' : 'not_matched';
        return $match;
    }

So if a method requires the role of bkeep (for bookkeeper) then the method that called verifyRole allows access. If not it's handled, and a redirect takes place.

Even Jeffrey in his video on authorization says it can be tricky at first to work out roles and permissions. There are several ways to do so.

I like doing it at controller method level, so yes I had to do some custom methods to handle that.

Roles and permissions can be one of the hardest parts of an application to setup, as there are many ways to achieve.

However for a query where a user can see only their data, but an admin can see all, again there are a couple of techniques used most often.

  • An if statement where one query is for admin other for user with whatever_id checked.

  • Separate methods for an admin vs a user.

For example, you could have:

  • an index method for users
  • an indexAdmin for admins

Usually when dealing with roles and permissions, you will have a fair share of if - else constructs.

Some use in view, I don't like them in the view, that's why I like them in controller where possible.

rawilk's avatar

@jlrdw

Some use in view, I don't like them in the view, that's why I like them in controller where possible.

How are you supposed to expose certain parts of a view based on a user's permissions if you don't check it in the view? The logic being performed to verify the role is still behind a method call and is no different than placing the same conditional inside a controller or somewhere else.

1 like
jlrdw's avatar

How are you supposed to expose certain parts of a view based on a user's permissions

As said, for user an index method, for admin, an indexadmin method. Two different views.

I didn't say I never do it in the view, I try to avoid if I can.

For user to see and edit there own data only, that can be checked in the controller.

rawilk's avatar

To me, it's more complicated to have two separate controller methods and two separate views when instead you could just have one conditional in a view that accomplishes the same thing. You're just making more work for yourself otherwise.

1 like
jlrdw's avatar

A follow up:

Warning, not a laravel example

But something similar I am currently working on in an app I am migrating:

Take a record that's going to be edited:

$data['row'] = $this->Pet->getPet($petid);
Cln::chkUserId($data['row'][0]->owner_id);

And a method to make sure the logged in user owns that record:

    public static function chkUserId($userid)
    {
        if ($userid === Session::get('owner') || Session::get('isadmin') === 'admin') {
            return;
        } else {
            Url::redirect('admin/admin'); // or where ever
        }
        return false;
    }

But this should never get hit. The only time it would if the user manually places an id in the url.

I am still working on roles in laravel, not finished yet, I had separate tables prior for login.

siangboon's avatar

before the view, you may try to tinker or dd() the results of $page->permissions in the hasAnyRole method or even before to double check the TYPE or the VALUE is what you expected to be used in the hasAnyRole method.

Please or to participate in this conversation.