Idiomatic way in Laravel to manage permissions with field level specificity - laravel

I am new to Laravel and I want to make data in my database available via RESTFUL API. I need to control permissions of data objects with field level specificity. I was curious what is the idiomatic way to do this in Laravel?
For example, I will have a database table called PrintMachine that has the fields Id,MachineName,ActivityStatus,ManufacturingYear. I want to assign the following permissions:
Web Administrators get Read and Edit access to all records and all fields in PrintMachine
Factory Managers get Read and Edit access to the PrintMachine.MachineName and PrintMachine.ActivityStatus fields for all records and get no access to any other fields in PrintMachine.
Floor Operators get Read access to the PrintMachine.MachineName field for all records and get no access to any other fields in PrintMachine.
People told me to consider Spatie Module and also read Gates and Policies, but it's not clear how either achieves field level permissions on their own.
The other option I was considering was to custom create my own solution by:
for GET requests, create three ViewModels called PrintMachineAdmin,PrintMachineManager,PrintMachineOperator, each class with properties accessible to the corresponding roles.
for POST/PUT requests, I'll have to write my own conditional statements to validate data based on the users roles
Is there a more idiomatic way to develop the a feature for field level permissions for restful apis?

So many options. An implementation of role and permission structure can achieve this and you can most certainly do this via the Spatie Module.
Eg adapted from spatie documentation:
$role = Role::create(['name' => 'Manager']); //db has roles table
//or if already created
//$role = Role::where('name', 'Manager')->first();
$permission = Permission::create(['name' => 'edit PrintMachine.MachineName']); //db permissions table
$role->givePermissionTo($permission); //now manager role has been assigned permission to edit machine name.
//assigning role to user
$user = User::create(['name'=> 'Manager User']); //or get existing
$user->assigneRole($role); //now this user has edit access to machine name
//to see if user has access
if( $user->hasPermissionTo('edit PrintMachine.MachineName') )
//do efit
//OR if you want to check using role
if( $user->hasRole('Manager')
//do manager stuff
//and in view you can use #can blade directive
#can( 'edit PrintMachine.MachineName' )
//authenticated user can edit machine name //show edit button/form
#endcan
//similarly #role directive will do the check using role
For super admins in AuthServiceProvider's boot method.
Gate::before(function ($user, $ability) {
return $user->hasRole('Super Admin') ? true : null;
});
Gate's before method precedes all other gate operations so all other permissions can be overridden here.

Related

Laravel scope query only for users - exclude result for admin

I am very new into programming and trying to make some work on Laravel / Voyager.
I have a Customers table and on this table there is also Customer_Representative field where I can select / assign customer representatives from dropdown list.
What I am trying to achieve is I want each users with their assigned roles (Customer Representative) to list customers only assigned for them.
I am using this below code, but I am not able to see list of customers that other users created. I can only see the customers I / Admin created but If I login with their details I can see their assigned customers.
So as an admin I want to be able to see all customers, so I can also edit them with my login credentials.
public function scopeCurrentUser($query)
{
return $query->where('Customer_Representative', Auth::user()->id);
}
I saw many suggested to use if but I couldn't figure out how to do it.
Appreciate your supports !
If I understand correctly, you want to display:
admin users - all users
non-admin users - only assigned users
You can either change the query in controller, but if you want to do it in scope I suggest something like this:
public function scopeCurrentUser($query)
{
return $query->when(auth()->user()->is_not_admin, function ($q) {
$q->where('Customer_Representative', auth()->user()->id)
});
}
You change the auth()->user()->is_not_admin to your condition for non-admin validation. The scope utilizes the ->when() function to append the condition to query only if the condition (in this case if authenticated user is not an admin) is true.
So if authenticated user is not an admin, his query will be filtered by Customer_Representative.

How to update a user using the 'Ion Auth' authentication library in CodeIgniter 4 framework

Below is my code snippet. I want to reduce the balance of a user in the database using Codeigniter 4?
dd($this->ionAuth->update($this->ionAuth->users()->row()->id, ['balance' => 1000]));
*I'm using Ion Auth for updating.
It's just a big burden when updating the database using modelling data.
It looks like you intend to use $this->ion_auth->user() instead of $this->ion_auth->users().
Also keep in mind that executing a dump and die on $this->ion_auth->update(...) returns a boolean not the updated user data.
References:
users() gets all users.
users()
Get the users.
Parameters
'Group IDs, group names, or group IDs and names' - array OPTIONAL. If an array of group ids, of group names, or of group ids and names are passed (or a single group id or name) this will return the users in those groups.
Usage
$users = $this->ion_auth->users()->result(); // get all users
user() gets a single user.
user()
Get a user.
Parameters
'Id' - integer OPTIONAL. If a user id is not passed the id of the currently logged in user will be used.
Usage
$user = $this->ion_auth->user()->row();
echo $user->email;
look here authentcate library for ci4
https://github.com/lonnieezell/myth-auth
go there download it
ionAuth is not compablitablke with ci4

Laravel: Check if the field was filled in the route, using Trait and Scope

I have an api that I am implementing multi-tenant based on an additional column in the tables.
For this I created a trait that implements a
static::addGlobalScope() and static::creating().
I have a user_idXtenant_id table. In this table I store the accesses that the user has.
My Route looks like this:
Route::get('{tenant_id}/products', function ($tenant_id) {
return App\Products::where(['tenant_id' => $tenant_id])->get();
})->middleware('role_or_permission:admin|seller|get-products');
Route::get('products', function () {
return App\Products::get();
})->middleware('role_or_permission:admin|seller|get-products');
The idea is that in the first route it is verified if the user has access to tenant_id and if he has access, return only the products of that tenant_id (here Polices can be useful and solve the problem).
The second route, on the other hand, must return all products of all tenant_id that the user has access to. For this, I use static :: addGlobalScope() to set the tenants that the user has access to in this way:
$builder->whereIn('tenant_id', $tenants);
The question is how to check in GlobalScope if tenant_id was filled in the model. So, if it is present, I only check the permission and if it is not present I include the tenant_id that the user has access to.
I hope I have been able to adequately exemplify the problem.
Any help is most welcome.
Thank you!

Parse - avoid sharing information in specific column of a class

I've got a question about the best way to allow user's information to be visible between users in certain situations.
I have certain columns in User class which are private to the user.
In some activity i'm pointing to user object as 'postedBy' or something else,In this case the entire data regarding user is getting shared.
My question is how to restrict user to get some columns in User class??
usually if you want to restrict an access in parse it should be done via ACL. In ACL you can create role for users who can read/write to the class.
ACL are executed on a class level and not on a column level. In order to expose part of the fields i think you have 2 options:
Create one to one realtionship from your User class to another Class. the second class will contain all columns that not all users can see and for this class create ACL's with the users/roles that can view this data and when you will execute your query only the users with sufficient permissions will be able to get this data
The second option is when you want to avoid relationships here you can use the select option under query. Select allows you to select specific fields of the class and the query will return only the fields that you specified under the select. here is a code snippet from parse docs which explain how to use select (in JS):
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.select("score", "playerName");
query.find().then(function(results) {
// each of results will only have the selected fields available.
});
Hope its clear now :)

Laravel 4: Restrict Access to Views Based on Permissions

I am building a series of forms in Laravel 4 with Doctrine 2. I want to be able to restrict access to each forms subsystem based on a user's level of permission (none, view, view and edit, view edit and delete).
In my database I have a table where each form subsection is stored (id, form_name, view_foldername) called "libForms". I also have a "users" table with all of the typical user information. When a new user is added, a third table, "permissions" gets populated with an access level of '0' (none) for each form currently in the system for that particular user.
When a new form is created, I also have it set up to where a new directory is created in the app/views directory. The name of this directory is a camelCase version of the form's name.
What I want to do is restrict access to any view within app/views/folderName for users that have an access level of '0' (none). Any user without access should be spit back to the homepage.
So far I have come up with trying something like:
Route::filter('formAuth', function()
{
$entityManager = App::make('Doctrine\ORM\EntityManagerInterface');
//get current user
$current_user = $entityManager->getRepository('User')->find(Session::get('my_userid'));
//check user's permission level for this section of forms
$form_route = $entityManager->getRepository('LibForm')->findOneBy(array('route_name' => Request::segment(1)));
...
});
And then calling this filter in the Controller's constructor.
$this->beforeFilter('formAuth');
I don't assume any of this is close to being correct and I am just confusing myself even more every time I think of something else!

Resources