Treat Laravel multi auth users as a unique user class - laravel

I have been struggling with this problem for couple of days and I've searched everywhere but couldn't find a logical solution.
I need multiple types of users in my project(admin, customer) because I need completely different backend logic for each type. So I decided to use multi-auth method in laravel(which AFAIK is the best solution for these cases). So I have multiple user classes for each type(and multiple tables in DB) including Admin and User classes. AdminAuth and UserAuth classes manage the Login and Register logic and routes are handled using middlewares.
Up till now there is no problem. The problem is that I need to use a single user class in another classes. For example consider the messaging logic(and there are many many similar use cases):
a Message class Model should have:
protected $fillable = [
'from_id', 'to_id', 'content', 'state'
];
public function sender(){
return $this->belongsTo(**User::class**);
}
public function receiver(){
return $this->belongsTo(**User::class**);
}
...
In the above model, I need to specify the User::class for senders and receivers, which can be either admins or users. So how can I tell Eloquent to use both models. Is it even possible? If not, what is the solution here?
I thought of using a higher level class named Person, for example, to hold the Admin or User object instances, but this way ORM can't manage to retrieve or store users from/in the appropriate tables automatically.
Any Suggestion is greatly appreciated.

I would advise you to use the following guidelines to handle such functionality; create a model for each user type but all of them should have a relationship with Laravel's default user class by keeping the user's id. Also, keep general properties in the user class and specific properties in each sub class, like customer's can have addresses and admins can have phone numbers, while the common things like the username can be kept in the user model. Then you won't need multiply forms for login, when a user logs in, you redirectly accordingly to the user's type in the default user record. Now for your messaging problem, use user the default user model to establish the relationship in messages as you shown above. Then defenping on the user's type, grant him different priviledges or features in the chat.

Related

How To: A Laravel Auth User Provider that finds users indirectly

My Laravel project involves businesses and their employees. The main Eloquent models are Businesses, Users and Roles. A User can have multiple Roles, each with a different Business.
When it comes to authentication, the Laravel Auth setup is a good fit, with one exception: A User does not have an email address. Instead, each of their Roles has an email address, and the user can log in using any one of these.
My user object has the password and remember_token fields. It seems to me that this object should still implement the Illuminate\Contracts\Auth\Authenticatable interface, and that it should do so by importing the Illuminate\Auth\Authenticatable trait. Does this sound right?
When it comes to the Illuminate\Contracts\Auth\UserProvider interface:
I think that I can extend the Eloquent provider implementation, Illuminate\Auth\EloquentUserProvider, and override only the retrieveByCredentials() method, but I am not sure. Will I need to override other methods as well?
If I do extend the Eloquent provider implementation, how do I go about injecting the $hasher and $model arguments when I register the new user provider in the boot() method of my AuthServiceProvider. Where do these values come from (see below)?
public function boot()
{
$this->registerPolicies();
Auth::provider('role', function ($app) {
$hasher = ''; // ????
$model = ''; // ???
return new UserViaRoleProvider($hasher, $model);
});
}
After some experimentation, I found that it was easier to create my own implementation of the UserProvider interface. The only method which required a bit of thought was retrieveByCredentials(). It searches for the Role, then returns the related user.
Although I was successful in logging in, I ultimately abandoned the approach because there are other parts of the Auth system that assume there is a 1-to-1 relationship between user and email. For example, the Password Reset functionality.

Authorization Policy without model

I need to authorize users on a forum.
So in blade, I have #can('editPost', $post) before showing the form to reply to a topic. My PostPolicy class has a editPost method that validates to true if it's the users own post.
However, the issue appears when I want to do a simple check, like deletePost(). This checks to see if Auth::user()->isAdmin
public function deletePost(User $user) {
return Auth::user()->isAdmin;
// return $user->isAdmin
}
However, this won't even get called, since I'm not passing an instance of Post
My real world application is much more complicated, but I'm using isAdmin as a simple example.
I guess defining $gate->define('deletePost', 'App\Policies\PostPolicy#deletePost'); in AuthServiceProvider could work, but would end up separating my definitions and methods, and ultimately for a large app clutter the AuthServiceProvider
When you register a policy it is the classname that is used to route checks to the class, so in order to get routed to the policy you can just pass the class name of the type you registered it with.
Try using #can('delete', Post::class) and see if that gets you there
refer to
Illuminate\Auth\Access\Gate::firstArgumentCorrespondsToPolicy
EDIT
After a little more diggin I found this
https://github.com/laravel/framework/commit/70f75255808ffc96275e6f2f356616dd2e163434#diff-961368895033e553787b301c3be0e17a
so it looks like if you on version 5.1.23 then you will be able to pass a string otherwise your will need to just pass new Post
In controllers
$this->authorize('<ability>', <Class-With-Rule::class> | <Full-Path-To-Class>);
In Blade view
#can('<ability>', <Class-With-Rule>::class> | <Full-Path-To-Class>)
In Eloquent model
$user->can('<ability>', <Class-With-Rule>::class> | <Full-Path-To-Class>);
Methods Without Models:
Some policy methods only receive the currently authenticated user and not an instance of the model they authorize. This situation is most common when authorizing create actions. For example, if you are creating a blog, you may wish to check if a user is authorized to create any posts at all.
When defining policy methods that will not receive a model instance, such as a create method, it will not receive a model instance. Instead, you should define the method as only expecting the authenticated user:
https://laravel.com/docs/7.x/authorization

ASP.NET WEB API 2: Role or Claim dependent model validation

I have a unique requirement that I'm not sure how to handle. We are working with an underlying repository that allows for a quite a bit of flexibility with regards to parameters. The Controller services are injected as "service" objects into a "Service" Property for our controller classes and they wrap the calls to entity framework.
eg.
public UserController:ApiController{
public IUserSvc Service {get;set}
public UserController(IUserSvc service){
this.Service=service;
}
}
This part is handled by Autofac and all is well here.
Next, we have the standard GET,POST,PUT,DELETE,PATCH methods in the controller that accept a SINGLE user model. In other words, there is only ONE user model that is ever used, and therein lies the problem.
While the underlying service class just handles the passing of data back and forth, it pushes the requirement of the granular control of validation up the pipe. This isn't abnormal to me.
Given that we have a single API that uses models with validation attributes, we've run into an issue where different apps that call into the api require different types of validation. The model structure is fine. It's just that some properties, depending on "who you are" and what HTTPMethod is sent, either are or are not validated.
ex:
public class User{
public int UserID {get;set}
public string Name {get;set;}
}
Let's take 2 scenarios:
1. Basic User
2. System User
As a basic user, UserID is required for: GET, PUT,PATCH ( and technically delete too but it's not used). It is not required for POST because that would be creating their own user.
As a system user, UserID is NOT required in GET but is required in PUT, PATCH, DELETE.
So I am having a hard time trying to figure out how to do this without making one api for Basic User with their own models and one for System User.
I wanted to keep this high in the pipe so I wasn't doing this in the controller api methods, i.e. Check roles/claims, create/cast/or otherwise map bound model to specific concrete model per role/claim and then run validation and THEN return model binding errors if any. That's a lot of gunk in the method and I would prefer this to be on an attribute of the method or api controller.
Is there any way to do a type of model binding and or model validation based on "who you are"? That could be by role or claim?

Can one controller point to different models?

i am currently developing a login and registration system,
The login system(its own controller, model and view) includes function such as:
validate, if_uname_exists, if_email_exists, etc
registration system(its own controller, model and view) includes functions:
register,send_activation,send_email, etc
However i have a need to make a user controller, which has the username as a data member, and i need to call on functions such as is_admin(), update_profile(). So my doubt is, should those functions be included a user model, or rather can i have them in another model, for example: login model or maybe a profile model?
Are there any best practices to follow on the same?
Thanks alot
yes absolutely. one controller many models.
another thing to consider - and note not everyone will approve of this but lets say you have a User model and then you need other models that are related to User but different. you can create a user.php model and then create a folder also named user. your model directory structure will then show your app structure like
user.php
user/create.php
user/emailnews.php
user/relatedcontent.php
this allows you to have shorter model names - and it still all makes sense. typically you would then have abstract methods in the user model and call specifics from the models in the folder. even if emailnews only has one method - breaking it out like that helps to document your application.

Zend Framework User Authentication (MVC question)

I'm getting some trouble understanding the MVC concepts.
I'm building a User model, you know? Application_Model_Users. They say that the models should only contain the structure... and the business logic should be put in the controller.
So, consider a function called authenticate($user, $password). This function will return true if the username and password entered is valid or false otherwise. Where should I put this function? In the controller Authentication or in the model Users?
Thank you!
Related to the Model, whenever you need to retrieve data(from DB, Web service, filesystem) or save data, you need a model to do the job. In MVC, a model is not understood as a mapped table, maybe more like a mapper. Zend has some info about this at their site, it could help you understanding mvc a bit more.
When it comes to user authentication, you should certainly implement the authenticate function inside the Users model, I would think you will do a database check against a table or similar.
Just in case you are not already using it, Zend comes with a package for auhtentication: Zend_Auth (http://framework.zend.com/manual/en/zend.auth.html) , it could speed up implementing the security at your application.
Although Model operations often include storage operations (DB, servicer, etc), it is not limited to that. Model, as far as I know, should countain Business logic entities, this is, classes that represent your business entities, like User, Person, Customer, etc. Each class should define its own operation methods, in example, a Person model class should allow you to get a person's name, calculate his/her age according to his/her birth date, etc.
Also, there should be specialized classes for Model storage and retrieval. With these classes you could fetch all your Customers, or only one, using certain conditions, etc, or save a modified Customer class instance (in example, a customer changed his/her address or phone number).
This separates the storage/retrieval operations from Business login operations.
So, according to your question, your model could have a class that allows you to find one user by its user name and password. If the user is found, you could return a Model_User class instance (in example). Then, using the standard Zend_Auth class, or extending it to create your own authentication class, you can use some Login form parameters to perform the user authentication.
Follow the Zend Framework quick start guide, there are the basics about MVC in Zend Framework. Also, there you will find some resources about Zend_Db and related classes, to allow DB interaction. There are also Zend_Db_Table, Zend_Db_Table_Rowset and Zend_Db_Table_Row classes, that you could extend to fit your model storage needs.
I have a personal solution where I extend Zend_Db_Table for my (in example) Model_UserTable class, used to store or query my Model_User entities. And my Model_User class extends Zend_Db_Table_Row.

Resources