Hi there,
Currently I have two users: Super Admin, Normal User
As far as I understand, the second parameter is the permission associated with the role that I send as the first parameter.
That makes me ask, is there any way I can validate that even if the permission is not associated with the role, I can perform the actions related to that permission?
This is my current route:
Route::group(['prefix' => 'admin','middleware' => 'auth'], function () {
Route::middleware(['role:User,view_profile'])->group(function () {
Route::get('/home', 'HomeController@index')->name('admin.home');
});
});
If I log in with my admin user I can not access that route even if I have the permission.
The same thing happens if I login with my normal user:
Route::group(['prefix' => 'admin','middleware' => 'auth'], function () {
Route::middleware(['role:Admin,view_profile'])->group(function () {
Route::get('/home', 'HomeController@index')->name('admin.home');
});
});
Being able to enter certain routes regardless of whether I have the role, just having the permission is enough.
_This does not apply to all routes._
A practical example of what I want to achieve:
I need my normal user to enter your profile and update it (if applicable) and also I want you to have the possibility to write a post.
Obviously you must have an additional permission that would be add_post
My super admin having all the permissions obviously can enter and create their own post additional to the possibility of accepting the post that the users send.
Please @freekmurze can you helpme with this?
Thanks for the explanation, but I'm not sure I understand your question correctly.
Are you aware that you can associate users with permissions directly? A role is just an optional thing.
Laravel also allows some logic to be run before checking the permission. This is useful for creating super admin like capabilities. More info here: https://laravel.com/docs/5.4/authorization#gates
@freekmurze thanks!!
so i created a superadmin role and gave it permission to "do everything". what do I need to do so that every permission check that I make, it allows a user with the permission "do everything" to do it eventhough the super admin user does not have specific permission to do that?
say i wanna check $user->hasPermissionTo('edit articles');
it should allow it because the user has the permission "do everything". I believe gates and auth help with this but I don't know how to implement it :(
@GDanielRG Me neither, but what I did was to create the number of roles needed according to my application with the corresponding permissions and it works without problems.
@abr4xas but you don't have the concept of super admin right?
@GDanielRG yes, super admin with all permissions and admin with few.
@abr4xas but I don't want to add every permission to the super admin role, I want it to autmatically always give permission to the superadmin role, so if I create new roles with different permissions in the future, I don't want to need to add them to the super admin
So you want to check if a user has a specific permission ('edit articles') or has a specific role ('superadmin')?
both. Specifically what I want to do is avoid having to give all the existing permissions to the super admin and the future ones. By the default whener I check for a permission if the user is superadmin just allow it eventhough the user may not have that specific permission im checking for.
I understand. In the app I am putting together, there are three roles, but it's such a small app that what I have done is exactly what you want to avoid: just added _all_ the permissions to the superuser role.
What I think you need is to create the 'do anything' permission, add it to the admin role, and then use the method hasAnyPermission to check:
$user->hasAnyPermission(['edit articles', 'do anything']);
I was trying to avoid something like that. Looking for some code modification in the auth or something I dunno. I guess that works but i will need to do it that way across the whole project. Thanks @vaughany
I think you need two middleware:
1.- to check role
2.- to check permission
Looks like the problem why $gate->before will not work when using middleware is because the middleware is using Auth::user()->hasAnyPermission(...$permission) instead of Auth::user()->can(...$permission).
https://github.com/spatie/laravel-permission/blob/master/src/Middlewares/PermissionMiddleware.php
@darwinluague wrote:
Looks like the problem why $gate->before will not work when using middleware is because the middleware is using Auth::user()->hasAnyPermission(...$permission) instead of Auth::user()->can(...$permission).
I'm not sure that's the root issue, since hasAnyPermission is an alias for can anyway.
For simple super-admin implementation, the gate->before works fine, as long as all tests for authorization use a test for the "permission", and not for a "role". ie: user->can('something') or @can('something') .... not user->hasRole('role name')
When you call hasAnyPermission the gate->before will not trigger because it checks directly to the database/cache.
@darwinluague I see your point:
As of v2.5.0, the PermissionMiddleware uses hasAnyPermission, which does a direct database lookup, ignoring the cache.
(My point earlier about can being an alias is only correct insomuch as can does the same lookup, but from cache first. Not the other way around.)
Granted, apart from doing extra database queries because it's ignoring the cache, it should still be giving the same results.
Toying with a PR to fix this discrepancy, by making the PermissionMiddleware use can directly: https://github.com/spatie/laravel-permission/pull/444
Realise this is almost a year old, but this is the first mention of the below (using roles for super admin) that I've seen in the issues:
For simple super-admin implementation, the gate->before works fine, as long as all tests for authorization use a test for the "permission", and not for a "role". ie: user->can('something') or @can('something') .... not user->hasRole('role name')
This is where I'm struggling - I could add "super_admin" role to every route, but this is tedious. Is there a better way? As I understand it, the Gate::before functionality wouldn't work for that...
@ediblemanager I think you mean this?
https://docs.spatie.be/laravel-permission/v2/basic-usage/super-admin/
@drbyte I might be misunderstanding, but doesn't the Gate::before only apply when using permissions? In my routes I use roles to determine access. I'd gladly be wrong on this and have it working!
Apologies, yes, the Gate interactions with this package are all permission-related, not role-related.
I suppose you could copy the RoleMiddleware into your app and customize it to first check whether the logged in user has your super-admin role.
@drbyte thanks for the heads up - I'll take a look at this. Is the way I'm doing things with roles ill-advised and therefore not supported, or just uncommon? Don't want to fall into a nasty trap!
@ediblemanager
I've always found it better to base my app on permissions. I use roles to assign those permissions to the users as a way of "grouping" those assignments. But in my application logic I base things primarily around permission to do whatever action or gain access to whatever controller, etc.
Initially I started doing things based on roles but most of the time ended up having to break things down into smaller chunks and therefore just determined it simpler to work with smaller moving parts. I can't recall where I read someone posting about moving strictly to permissions as well, but after taking the plunge I've found most apps more manageable this way.
I'm sure there are excellent use-cases for focusing on roles only. I just haven't found it practical.
I can see why the granularity that using permissions appeals. I'll stick with roles at the moment, but will probably find myself moving to permissions like you did.
Thanks for your help, @drbyte !