How to check user roles in canAccessPanel()

Hello, I can't seem to find the code to use to check if a role is assigned to a user from database into canAccessPanel() I need to check: role_user pivot table Admin has role_id 1, user_id 1 Company user has role_id 2, user_id 2 (for this example, but many users will have role_id 2) I have a different panel for each... AdminPanelProvider for Admin Role, CompanyPanelProvider for Company Role I tried checking documentation and online and can't figure this out 😦 Thank you in advanced!
34 Replies
tuto1902
tuto190210mo ago
What I would do is add this helper function to the User model
public function hasRole($userRoles)
{
if (is_array($userRoles)) {
$roles = $this->roles->whereIn('name', $userRoles);
} else {
$roles = $this->roles->where('name', $userRoles);
}
if ($roles->isEmpty()) {
return false;
}
return true;
}
public function hasRole($userRoles)
{
if (is_array($userRoles)) {
$roles = $this->roles->whereIn('name', $userRoles);
} else {
$roles = $this->roles->where('name', $userRoles);
}
if ($roles->isEmpty()) {
return false;
}
return true;
}
Then, in the canAccessPanel method
return auth()->user()->hasRole('admin');
// or
return auth()->user()->hasRole(['admin', 'company']);
return auth()->user()->hasRole('admin');
// or
return auth()->user()->hasRole(['admin', 'company']);
JamesTechDude
JamesTechDude10mo ago
This definitely works so far, is there a way to specify which role gets to view which panel? For example, Company gets CompanyPanelProvider, and Admin gets AdminPanelProvider?
tuto1902
tuto190210mo ago
I personally haven't found one yet 🤷‍♂️
JamesTechDude
JamesTechDude10mo ago
Same, I can't find it for the life of me :/ must not be a way to do that yet :/ But how do I prevent a Company user from switching to the Admin panel? Seems like it should be implemented somehow haha Especially because all they need to do is just change the endpoint URL and they would get access easily
tuto1902
tuto190210mo ago
Well, if the Admin panel only allows access to users with admin role, I would guess they'd just get a 403 error page
tuto1902
tuto190210mo ago
Yup, that's exactly what happens
No description
tuto1902
tuto190210mo ago
Well, there's an idea. You can customize Laravel error pages and maybe offer a link to take the user to the proper panel based on their role
JamesTechDude
JamesTechDude10mo ago
True but then how do I allow access to Company panel? Haha If I use: return auth()->user()->hasRole(['admin', 'company']); This would let Admin & Company see both panels :/ If I remove Company, then only Admin can see both panels :/
tuto1902
tuto190210mo ago
Ok, walk me through the process here: - Admin users can access both panels (as they should) - Company users can only access the Company panel - If a Company user logs in using the Admin panel, they get a 403 This would return true, only if the currently logged in user has at least one of those roles (ie. an admin user)
return auth()->user()->hasRole(['admin', 'company']);
return auth()->user()->hasRole(['admin', 'company']);
So, you would want the Company user to only have the 'company' role
JamesTechDude
JamesTechDude10mo ago
Yes those steps are correct And yes, Company user would only have 'company' role and can only access the Company panel (get 403 for Admin panel)
tuto1902
tuto190210mo ago
Oh good, I got it right. So yeah. If you do php artisan vendor:publish --tag=laravel-errors, you can customize the 403 page and render a link based on the user roles. You have access to the auth() helper withing any template. So if I'm a Company user in the admin panel, the link would say "Looks like you're lost, try logging in the <a href="...">Company panel</a>"
JamesTechDude
JamesTechDude10mo ago
Interesting, how does it know that when using return auth()->user()->hasRole(['admin', 'company']); ?
tuto1902
tuto190210mo ago
I would use it like this:
@if (auth()->user()->hasRole('company')
Looks like you're lost, try logging in the <a href="...">Company panel</a>
@endif
@if (auth()->user()->hasRole('company')
Looks like you're lost, try logging in the <a href="...">Company panel</a>
@endif
Because we already know that the Admin user would never get a 403 and I may have confused you before. The canAccessPanel() method of the Admin panel would have auth()->user()->hasRole('admin'). Allowing only admin users to that panel
JamesTechDude
JamesTechDude10mo ago
Interesting, how does it know to let the company access the company panel tho 😆 Sorry this filament user access part is really new for me is canAccessPanel only for admins?
tuto1902
tuto190210mo ago
You would add auth()->user()->hasRole('company') to the canAccessPanel() of the Company panel canAccessPanel is just a way of letting certain user see the current panel
JamesTechDude
JamesTechDude10mo ago
But if it's on the User model, how do we set it for the Company panel? If I set it to Admin then Company can't access any panels, if I set it to both Admin and Company, both can access both :/
tuto1902
tuto190210mo ago
I believe the panel instance is injected into the canAccessPanel() method
public function canAccessPanel(Panel $panel): bool
{
// ...
}
public function canAccessPanel(Panel $panel): bool
{
// ...
}
JamesTechDude
JamesTechDude10mo ago
OMG How am I so blind
tuto1902
tuto190210mo ago
haha $panel->getId() should help
JamesTechDude
JamesTechDude10mo ago
For reference, this is what worked (I called the Company Owner the Owner Role) public function canAccessPanel(Panel $panel): bool { $panelGetId = $panel->getId(); if(auth()->user()->hasRole(['Admin']) && $panelGetId == 'admin'){ return true; }elseif(auth()->user()->hasRole(['Owner']) && $panelGetId == 'company'){ return true; }else{ return false; } } Thank you for leading me in the right direction! I was so lost!
tuto1902
tuto190210mo ago
More than happy to help 👍
JamesTechDude
JamesTechDude10mo ago
I just realized I might have to change this around a bit, as Filament expects to use "company_user" table to determine who is a company user (instead of using the roles with company_id)
tuto1902
tuto190210mo ago
Yeah, you're right.
JamesTechDude
JamesTechDude10mo ago
So maybe it's better to get rid of roles all together and just check if they are in company_user table 😮 Or I should add role_id to company_user?
tuto1902
tuto190210mo ago
but, isn't company_user for multi-tenancy purposes?
JamesTechDude
JamesTechDude10mo ago
Yeah it is 😮 Man this is difficult My end goal is to have Admin Company Owner (just Owner for the role) Clients
tuto1902
tuto190210mo ago
I know. So you still need roles. Panels and Multi-Tenancy are different. As I understand it. You can have multiple panels. And each panel can have their own Tenants (as configured in the panel service provider).
JamesTechDude
JamesTechDude10mo ago
Yes that's correct I think my main confusion is how do I assign the Role to the specific User for the specific Company As Users can have multiple Companies, and Companies can have multiple Users, and a User can have multiple Roles within the same Company... I tried this: $user = auth()->user()->id; $company = Company::create($data); $role = Role::where('name', 'Owner')->first(); //assign pivot table $company->user()->attach(auth()->user()); //assign company owner role $user->attachRole($role); return $company; But it tells me: Call to a member function attachRole() on int
tuto1902
tuto190210mo ago
$user = auth()->user()->id; $user->attachRole($role); Do you see the issue there?
JamesTechDude
JamesTechDude10mo ago
Dang I think I need a break hahahha Yeah I see the issue, it's giving the User ID instead of the User Model :/
tuto1902
tuto190210mo ago
Yeah, sometimes is best to take a breath and clear your mind.
JamesTechDude
JamesTechDude10mo ago
Got it to work with this 😄 //create company, assign pivot table $company = Company::create($data); $company->user()->attach(auth()->user()); //assign company owner role $user = User::find(auth()->user()->id); $role = Role::find(2); //Owner Role $user->roles()->attach($role, ['company_id' => $company->id]); return $company; Now the question is if I leave assigned roles in the role_user table, or move role_id to the company_user table and get rid of the role_user table... decisions... I'll leave it since someone can be a client or a company owner in the same company Thank you! I'll stop buggin you now haha
tuto1902
tuto190210mo ago
🤣 It's no problem at all. I'm here to help
JamesTechDude
JamesTechDude10mo ago
😆 It's the abstract thinking that can really get to me sometimes haha In my User model, I have:
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}

public function hasRole($userRoles)
{
if (is_array($userRoles)) {
$roles = $this->roles->whereIn('name', $userRoles);
} else {
$roles = $this->roles->where('name', $userRoles);
}
if ($roles->isEmpty()) {
return false;
}
return true;
}

public function canAccessPanel(Panel $panel): bool
{
$panelGetId = $panel->getId();

return match($panelGetId) {
'admin' => auth()->user()->hasRole(['admin']),
'company' => auth()->user()->hasRole(['owner']),
'client' => auth()->user()->hasRole(['client']),
};
}
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}

public function hasRole($userRoles)
{
if (is_array($userRoles)) {
$roles = $this->roles->whereIn('name', $userRoles);
} else {
$roles = $this->roles->where('name', $userRoles);
}
if ($roles->isEmpty()) {
return false;
}
return true;
}

public function canAccessPanel(Panel $panel): bool
{
$panelGetId = $panel->getId();

return match($panelGetId) {
'admin' => auth()->user()->hasRole(['admin']),
'company' => auth()->user()->hasRole(['owner']),
'client' => auth()->user()->hasRole(['client']),
};
}
This is giving an error saying undefined method 'hasRole' Disregard, it was VS Code giving this error even though it's working... intelliphense (or whatever) for ya
Want results from more Discord servers?
Add your server