Laravel user management - laravel

In Laravel we can manage Users and Permissions easly but i've a problem with my application.
In my application a User is attached to One or Many department.
But a User can have different Role/Permission between departments. That is the problem. In the department One he can have a Admin Role and in the department Two he can only have a User Role. When the User switch between department i would like that his Role can be update.
How i can manage this in Laravel and Eloquent ?
Thank you for your help.
Jeffrey

Without seeing any of your code, I am forced to be fairly generic here. But here is the basic concept.
Architecture
Assuming you have tables like departments, users, roles, and permissions already, all you would need next is define a joining table. Something like this:
department_role_user
department_id // for this department
role_id // this role is assigned to
user_id // this user
Authorization
Define something like a hasPermissionTo() method on your User model.
Definition
class User
{
public function hasPermissionTo($action, $department)
{
// first get permission
$permission = Permission::where('action', $action)->first();
// get all roles which have this permission
$roles = $permission->roles;
return DB::table('department_role_user')
->where('user_id', $this->id) // current user
->where('department_id', $department->id) // the dept
->whereIn('role_id', $roles->pluck('id')) // any of the roles
->exists();
}
}
Usage
And use it like so.
if ($user->hasPermissionTo('do-something', $someDept)) {
// allow action
} else {
// no way
}
This should also work nicely with Laravel's Gates and Policies. Just use your new hasPermissionTo() method inside your gate/policy definitions.

Related

Laravel: sync many to many on a subset of rows

There is a multi-tenant laravel application that is implemented in a single database. There are models User and Role with the following relation in User model:
public function roles(): BelongsToMany
{
$relation = $this->belongsToMany(Roles::class, 'role_users', 'user_id', 'role_id')->withTimestamps()->withPivot('tenant_id');
$relation = $relation->where(function ($query) {
$query->where('tenant_id', Tenant::current()->id);
});
return $relation;
}
The role_users table contains user_id, role_id, tenant_id. A user may present in multiple tenants, when I update roles of a user in a tenant, I need to only update the roles of the current tenant, not the user roles on all tenants. This the code I write :
$user->roles()->syncWithPivotValues($roles, ['tenant_id' => Tenant::current()->id]);
But it doesn't work and syncs all roles not the roles of the current tenant. How can I solve the problem?
You can use the wherePivot() method passing the tenant id.
You can find the documentation here: https://laravel.com/docs/9.x/eloquent-relationships#filtering-queries-via-intermediate-table-columns
The code should then look like this:
$user->roles()->wherePivot('tenant_id', Tenant::current()->id)->sync($roles);

Is removing the relations of a model, in a one-to-many relationship, and redefining the relations the best approach to peform update?

I have two models, user and permissions. 1 user can have many permissions, a user_id will have multiple occurrences on the permissions table. When updating an user I may change its permissions.
users permissions
id id
name user_id
With eloquent I do something like this:
$user = User::find(1);
$user->permission()->delete();
$user->permission()->create($permissions);
Although this code is very logical, it doesn't seem right to me. Finding the user, scanning the table to remove its permissions and reinserting new ones seems amateur, the deletion part doesn't seem right to me. To achieve one task I have to go through multiple processes.
If at least was something like this:
$user = User::find(1);
$user->permission()->recreate($permissions);
Of course recreate would have to be a built-in function and I am willing to code that functionality. Can't say if am doing things right.
Are you sure you are doing it rigth?
Since a user can have many permissions, you should have a user, permissions and a user_has_permissions or something like useR_permissions table.
users permissions user_has_permissions
id id user_id
name name permission_id
... ...
This is the relationships:
User permissions (in user model):
public function permissions()
{
return $this->belongsToMany(Permission::class, 'user_has_permissions');
}
To check if the user has permissions (in user model):
public function hasPermission($permissionId)
{
return null !== $this->permissions()->where('permission_id', $permissionId)->first();
}
You can also have a roles table, that has many permissions:
users permissions user_has_permissions roles role_has_permissions user_has_role
id id user_id id role_id user_id
name name permission_id name permission_id role_id
... ... ...
Now, user can have permissions and permissions through roles.
The user roles (in user model):
public function roles()
{
return $this->belongsToMany(Role::class, 'user_has_roles');
}
The role permissions (in the Role model):
public function permissions()
{
return $this->belongsToMany(Permission::class, 'role_has_permissions');
}
To check if the user has permissions through roles (in the user model):
public function hasPermissionThroughRoles($permissionId)
{
$roles = $this->roles;
foreach($roles as $role){
if($this->roles->contains($permissionId)
return true;
}
}
You can modify the hasPermissios function to check if the user has permission through roles, and if yes, grant access:
public function hasPermission($permissionId)
{
return (bool)($this->permissions()->where('permission_id', $permissionId)->first() || $this->hasPermissionThroughRoles($permissionId));
}
From laravel docs:
Eloquent also provides a few additional helper methods to make working with related models more convenient. For example, let's imagine a user can have many roles and a role can have many users. To attach a role to a user by inserting a record in the intermediate table that joins the models, use the attach method.
With the provided code snippets, you can add permission or role to the user with
$user = User::find(1);
$user->permissions()->attach(1);
$user->roles()->attach(1);
or remove permissions/roles:
$user = User::find(1);
$user->permissions()->detach(1);
$user->roles()->detach(1);
Check this package. The user permissions and roles (or group, as it is called in the package) management is easy with it.
Hope it helps.

How to limit access from pivot table? Laravel

I have tables:
user
id
name
companies
id
name
company_user
company_id
user_id
Tables has Many To Many relationships.
As it complicated relationship for me, I can't find way how to make this limit, when user can see companies that was created by this user. (probably not well experienced)
Now I have this, but user can see any company
CompanyController:
public function show($company_id)
{
$company = Company::where('id', $company_id)->firstOrFail();
return view('company.settings', compact('company'));
}
So tip me please how to make user can see only companies created by this user.
You can do this:
public function show($company_id)
{
$company = auth()->user()->companies()->findOrFail($company_id);
return view('company.settings', compact('company'));
}
It will scope the company to the currently logged in user (through the many-to-many relationship on the User model). If none is found, it will return 404.
Since it many to many relation, you can map one company to many users, also map one user to many companies. Check if you have not mistakenly assign the company to many user
Also the above code can be written the way
public function show($company_id)
{
$company = Company::findOrFail($company_id);
return view('company.settings', compact('company'));
}

Laravel roles and permissions

I am new with Laravel and i am trying to build an application based on roles, but in my case the user can have only one role (there is no a pivot table between users and roles) and we can create new role us we like(assign many permissions to one role). Any help? and thanks a lot
So here is one way I would do it.
You need 2 tables :
One table I would call "ranks", inside it you can have everything about the rank itself :
Its id of course, but also :
Is it an admin rank ? (all permissions)
What's it name ? ...
One table I would call "ranks_abilities", inside it you can have everything about what a rank can do
Therefore, it would have three columns : an id, a rank_id, and the name of the ability
And you need to put the rank_id inside the users table.
Note : if you wanna do it really nicely, you can have a table "abilities" containing all the possible abilities, and you'd reference their ids instead of the name
So how would it work ?
You would therefore have three models :
User
Rank
RanksAbility
Inside of your User model, you'd have a belongs_to relationship to the Rank model (call it rank)
Inside of the Rank model, you'd have a has_many relationship to the RanksAbility model (call it ranks_abilities)
I guess we are now fine with the database structure, let's get to the point of allowing to do something.
So, of course, where a login is required, you have the auth middleware that does it perfectly
Then, to handle the permissions itself, there are several ways to do it, here is one I would recommend.
Step 1 :
Create a policy for some action for example if you have posts you can create a PostPolicy (https://laravel.com/docs/5.4/authorization#creating-policies)
If, you want, for example, a permission so that a user can edit all posts, you'd have an update method in that PostPolicy
public function update(User $user, Post $post)
{
return $user->hasPermission('post.update'); // You can also add other permissions for example if the post belongs to your user I'd add || $post->user_id == $user->id
}
I would do something like that.
Then, you'd have to make the hasPermission method.
So, in your User model, you could put something like this :
public function hasPermission($permission){
if(!$this->relationLoaded('rank')){
$this->load('rank', 'rank.ranks_abilities');
}
if(!$this->rank){
return false;// If the user has no rank, return false
}
foreach($this->rank->rank_abilities as $ability){
if($permission === $ability->name){
return true;// If the user has the permission
}
}
return false;
}
And here the method is done.
Last step, you can use all the methods listed here https://laravel.com/docs/5.4/authorization#authorizing-actions-using-policies to avoid an user from doing something he can't.
Personally, I would do a FormRequest, and handle the authorization with it (https://laravel.com/docs/5.4/validation#authorizing-form-requests).
I hope to be clear, if you have any more questions go ahead
For setting up customized user roles and permissions, you may give a try to https://thewebtier.com/laravel/understanding-roles-permissions-laravel/.
It's a complete guide on how to setup roles and permissions in your Laravel project.

Laravel - How to create user control in Laravel base role

Hello I'm a newbie with Laravel, I wanna ask how to make user control in Laravel base user role,
I have 5 table
table menus
table user_menus
table roles
table user_roles
table users
and then I want to validate which user can access the menu
the example role_id 1 (administrator) can access menu 1 and 2 ('master maintenance' and 'user')
and if authentication then can access the module, if not then redirect to 404.
Please help me! I have no idea what should I do :(
I looking for many sites but I don't get any solution
Thanks for answer
I not sure because i don't have your database but i think you and set relation in you model for make it easy
in model UserRole add relation
public function usermenus()
{
return $this->hasMany('UserMenus', 'role_id', 'role_id');
}
in model UserMenus add relation
public function menus()
{
return $this->hasOne('Menus', 'menu_id', 'menu_id');
}
when you want to query data
$menus = UserRole::where('user_id', $userId)->with('usermenus.menus')->get()->toArray();
print_r($menus); exit;
//or use dd($menus); for print and die

Resources