I am getting to know the Laravel framework, and in the test application I am using the santigarcor/laratrust package to implement Roles and permissions.
For the project, I assumed that a user may have several profiles (One To Many) with assigned roles and permissions.
After logging in, the user is automatically assigned a default profile in the session, which he can change later.
For example:
User $user has a profiles: manager, editor and reader. Each profile has different roles/permissions.
The default profile is the editor. After logging in, I save to
Session::put('profile', $user->defaultProfile).
If I want to check the roles, e.g. in the controller, I can do:
$profile = Session::get('profile');
$profile->isAbleTo('edit-user');
But if i want to use middleware or blade directives #role(), #permission(), #ability() how to do it? best practice way?
Is it possible to easily map these methods so that they check not the user (auth()->user()) but his selected profile? Or I should write custom middleware and blade directives?
Since there was no answer here, I read a few and decided to use the built-in Gate functionality. So I can use Gate methods for authorizing abilities (allows, denies, check, any, none, authorize, can, cannot) and the authorization Blade directives (#can, #cannot, #canany).
The gates are defined dynamically:
\App\Models\Permission::get()->map(function($permission) {
Gate::define($permission->name, function($user) use ($permission) {
if (session()->has('profile')) {
$profile = session()->get('profile');
return optional($profile)->hasPermission($permission->name);
}
return false;
});
});
So for now I think is solved, but I will test it more.
Related
I found the way to add an admin guard.
But there are no documentation to customize the following functionality:
Auth::guard('admin')->attempt()
Auth::guard('admin')->user()
Auth::guard('admin')->check()
middleware('auth:admin')
I need to check an additional field of admin table to check if the admin can be logged in.
In Auth::guard('admin')->attempt(), I want to use SQL like this:
Admin::where('login_id', $request->input('login_id'))
->where('password', md5($request->input('password')))
->where('additional_field', [additional condition]);
By Auth::guard('admin')->user(), I want to get the result of SQL like this:
Admin::where('id', Auth::guard('admin')->id())
->where('additional_field', [additional condition]);
And both Auth::guard('admin')->check() and middleware('auth:admin') also should consider the additional condition in the code above.
Is there a way to customize them?
And, are there any other functionalities of Laravel's auth which I have to customize to satisfy the requirement of the additional condition above?
I'm using Laravel 8.
IF your additional stuff are some input like login_id and password
maybe this should work.
$cradentials= $request->only('email','password','additional stuff');
if( Auth::guard('admin')->attempt($cradentials) ){
//stuff here
}
I'm using laravel gates in my web.php, where i add middleware for can as follows
Route::post('/sellproducts', 'ProductController#Sell')->middleware('auth')->middleware('can:admin');
i want to add another rule for example can:admin or can:moderator so either of them is true, gate will allow
any ideas ?
I don't think you can use a logical or operator when enabling middleware for a route.
You could make a third Gate, that returns true when the user is either admin or moderator.
Another option is that you would create a ProductPolicy. In this policy you could create a sellProduct() method that checks if the user has the right roles:
public function sellProduct(User $user, Product $product)
{
// Return true when user is moderator or admin
}
You would have to call this method in your ProductController#Sell with:
$this->authorize('sellProduct', $product);
Take attention that gates and policies are meant to determine if a user is authorized to perform an action. This can be done by checking if the user has a certain role, or if the user is the owner of, in your case, a product. When you define a Gate as 'admin' things could get mixed up.
Route::post('/sellproducts', 'ProductController#Sell')->middleware('auth, can:admin');
i have codeigniter background. Now, i'm learning about laravel. So, i'm in this condition (Example), I'm trying to create a webapp, which has multiple users. The UsersType A , they can access menu a, menu b & menu c and UsersType B they only can access Menu a.
Now, i'm using https://github.com/lavary/laravel-menu . Well, if it's only have two types , i can write it manually. But, what if there are five types of user or more.
When i'm using codeigniter. I create 4 table Users , UsersType , Menu & MenuAccess. You must be understand how it's work. I just, play it with query then i show it.
UsersType (Users) -> TypeId (UsersType) -> MenuId (MenuAccess) -> MenuId (Menu)
I already use google and I found this https://github.com/Zizaco/entrust but what i can see from that package. It's only give the permission on the action (input,edit & delete)
So, Can i do my codeigniter way in my laravel ? Save my routes properties than show it in my rouotes/web.php (I don't know if it possible, haven't try it yet). sorry for my english.
What I would do is put a function in the User class which checks it's own permission and then returns a view which contains the menu that user has access to.
public function menu()
{
switch($this->role) {
case 'admin':
return view('menus.admin');
[etc]
}
}
Then in the view just check if the user is logged in and show the menu:
#if Auth::check()
{{ Auth::user->menu() }}
#endif
As mentioned in the comments,it sounds like what you want is the ability to conditionally display content based on whether a user has certain permissions.
There's a number of implementations of this. Essentially what they all do is store permissions that can be granted to users, and optionally store roles that allow permissions to be assigned to a role and then users can be given that role, automatically granting them the permissions associated with that role.
I've found spatie/laravel-permission which appears to be quite good. Then, if you pass your user model into the view, you can do something like this:
#if ($user->can('edit-posts'))
<a>Edit post</a>
#endif
That should be flexible enough that it can be reused for different permissions too. If that doesn't do the trick, then it's not hard to roll your own permission system using Laravel's authorization system and you should be able to use the can() method in the same way.
I currently work on a project where the User creates Models, that only he/she is allowed to see, edit or delete.
The Create Part done by Eloquent Relationships, but for the other operations I would like to combine it with Route Model binding and not manually in the controller. I tried solving it with middlewares, but I couldn't access the Ressource.
Can somebody point me to the right Direction, any best Practices are welcome!
Personally I use route model binding, but only allow the model to bind if the user owns the record.
This means that no matter what - people can never access someone elses record. So for example, in my route I can do
$router->get('property/{property}, ['uses' => PropertyController#show]);
Then in my RouteServiceProvider:
$router->bind('property', function($value) {
$property = \App\Property::findOrFail($value);
if ((int)$property->user_id !== (int)auth()->id()) {
abort (404);
}
return $property;
});
So in the example above - we have a property route, and it will try and find the property record given. It will then check that the user owns the record, otherwise it throws a 404 (but you could just redirect or something - up to you).
I have an MVC 5 application that I lock down by only allowing certain authenticated users to have access to specific actions within my controller. I utilize the authorize attribute at the top of the class allowing only the user(s) I want to gain access after login. I do this with the following attribute placed at top of my class...
[Authorize(Users="user1,user2")]
This works great! However, what if I don't want to recompile and deploy the application everytime I want to add a new user to this specific controller?
I thought I might add this in my web.config file under as a key like so...
<appSettings>
<add users="user1,user2"/>
</appSettings>
But when I try to access this key in my controller like so: [Authorize(Users=ConfigurationManager.AppSettings["users"])] I am getting an error: Cannot resolve symbol 'AppSettings'.
Is there a way to do this?
I'm not sure why an answer that didn't answer the question was accepted. Regardless, I thought it might be worth adding an answer for any future travelers.
While this functionality isn't provided out of the box, it's certainly possible by writing your own authorize attribute.
public class ConfigAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var allowedUsers = ConfigurationManager.AppSettings["CoolActionAllowedUsers"];
var allowedUsersArray = allowedUsers.Split(',');
if (httpContext.User.Identity != null && allowedUsersArray.Contains(httpContext.User.Identity.Name))
{
return true;
}
return false;
}
}
And to use the attribute:
[ConfigAuthorize]
public ActionResult CoolAction() {
//...
}
In the code above when your authorization is performed in AuthorizeCore, the configuration value from CoolActionAllowedUsers will be pulled into memory and the currently authenticated user will be verified if they are in the list of allowed users. If you make a change to your config file it won't be a problem; the application pool will automatically restart and the next time the code runs to read the config file your new value will be read.
I completely agree with #Shoe that roles should be used. Managing a list of users in your code is just a pain in the arse. In fact, at work, anytime I get a request for just one random user to have access to a page I always require a group to be setup. However the code above could apply to a list of roles as well.
Instead of using the Users parameter use the Roles parameter.
[Authorize(Roles="CanExecuteActions")]
Now you can manage what users have access to your controller by giving them this role. Any user without the role can't execute any actions of the controller.