I've 2 tables, Users and Customers and 2 different actions for them. so I need 2 authentication system. Users login with username and password, and customers login with and id and password.
I know cake default AuthComponent can handle just 1 model, User model. because 'userModel' can be string not array (isn't it?).
How can I use it with 2 models (and tables) with 2 login pages and 2 .... .
(note: I can't combine the 2 tables. they have different schemas)
Instead of trying to maintain 2 different Auth systems, I highly recommend you look into ACLs and AROs. This will allow you to associate users with different access groups - in your case you could have groups like 'Internal'1 and 'Customers', and each new user account is a member of one group or the other.
You can then grant permissions at a group level. Customer users have access to their content, Internal users have access to different content.
There is a good tutorial in the new CakePHP book: Simple Acl controlled Application
1 I assume when you refer to 'users' generically you mean internal users, but feel free to adapt the terminology and group names to your particular situation.
I would presume 2 separate logins areas or a radio button to suggest which login they are attempting.
Use that input as which table to auth against then your code should follow the same path.
if (customer) {
do customer stuff;
} elseif (user) {
do user stuff;
} else {
you didn't login;
}
When you create the registration forms for them try to get their data into different databases. So that you can treat them differently. For this purpose check the submit button ids and direct the data to appropriate tables. When inserting put id's as auto increments.
I would advise against discriminating users from customers in this situation. These issues can be resolved using roles. Before jumping to design, please read about Authentication, Authorization and Audit and Role-Based Access Control.
From my understanding, this is an overview of the authentication process (note that I am not a security expert):
The identification phase is concerned with obtaining user credentials. A simple form that retreives user's name and password would suffice.
The authentication phase represents the process that maps user credentials to an user. Basically, it identifies a identity provider and uses it to obtain an user id for the user credentials provided.
Viewed like services, they look something like this:
// You can have many IdentityProviders. This mecanism allows you to extend your
// authentication system so you can use any mechanism (WebDav, Kerberos, etc).
IIdentityProvider
{
// Returns a pozitive id if the user is found and the credentials are valid
// or zero if user credentials are invalid (or negative numbers that represent
// error codes).
UserID GetUser(UserCredentials)
}
IAuthenticationService
{
Session SignIn(UserCredentials)
void SignOut(Session)
}
DefaultIdentityProvider : IIdentityProvider
{
// Search the user in your database.
UserID GetUser(UserCredentials credentials)
}
AuthenticationService : IAuthenticationService
{
IIdentityProvider[] identityProviders
Session SignIn(UserCredentials credentials)
{
IIdentityProvider provider = identityProviders[credentials.Type]
Session session = null
if (provider)
{
UserID userID = provider.GetUser(credentials)
if (userID > 0)
{
session = new Session
session.UserID = userID
}
}
return session
}
void SignOut(Session session)
{
delete session
}
}
The autorization system says what can a user do with a resource. Resources can be any entity that your application manages. They have a type and an ID. Optionally, they can be part of one or more categories. Users can execute certain operations on a resource, depending on its type and categories. This is defined by a permission. Permissions are grouped in roles. You can assign zero or more roles to an user.
In your example, a customer is a role. A resource is, for example, a product. A product is represented by the Product type, it has an ID and can have some categories associated ("Electronics" and "Dangerous"). Operations can be viewed as variations of Create/Read/Update/Delete verbs. Now, the Customer role would contain a set of permissions that explicitely states what a user having this role can do with the managed resources. For example, a Customer can only Read certain informations about the product, but cannot Create, Update or Delete a product. Note that if a user has more than one role associated, it gains all the permissions from that roles (an union operation, not an intersection).
This only scratches the surface. For further reading, you can find on the Internet more articles that explain these concepts alot better. This is meant to point you in the right direction.
Related
I have an API built with Laravel that works with authentication tokens (the passport package). It is unclear to me what should be the best practice for resources that are accessed within an authenticated session.
Let me explain.
Let's say I would like to see the orders of a user as an administrator, I visit: /v1/users/5/orders and all orders get listed for user with ID 5.
But now the user with ID 5 is authenticated. What should the URL be to access his own orders resource?
Would that be: /v1/users/5/orders (and check if it's either an admin or the session belongs to the user with ID of 5)
OR /v1/my/orders
OR /v1/my-orders
OR /v1/orders (and use session ID of user 5, - OR list all results when admin)
It just gets confusing when on the same URL the orders can be listed because an admin wants to access it. Or it is actually the session user that wants to see them.
I would suggest using /v1/orders, that will display a collection of orders based on privileges:
- all orders in case of an admin session
- orders belonging to the authenticated user, in case of a less privileged user.
Adding a prefix like /my/orders or my-orders does not bring any value.
For the sub-collections I would keep the route /v1/users/5/orders that will allow admin to access user orders.
This is a pretty good tutorial that explains API resource naming: https://restfulapi.net/resource-naming/
I have done a lot of reading on this but nothing stands out. I already have a authentication and authorisation system that can handle multiple guards and user roles (user, admin, super admin etc.)
I am trying to find out what is the best way to separate the system into totally separate accounts which have the following;
No login section
Landing page. Anyone can see without login.
Admin Section
Admin side of the system has a super-admins and then multiple admin-users.
These users can see all data from every user who has an account on the client side.
Client Section
Each user account has an owner who deals with billing, their own user admin etc.
Each client account also has a number of users (admin-users, editor-users etc.) with varying permissions.
Users on this side should only ever be able to see their own accounts data. They should not be able to ever see other accounts data.
Before Laravel, I would have an accounts table and assign a unique key to each account. Then a separate users table would contain the user along with their account key.
All database tables from this point onwards (posts, products, shipments etc.) would also have this key to ensure that the user account could only see their own data.
On top of this there would be permission tables, for granular control of what each user from either side can see.
Is my original way still suited to Laravel or is there a better way?
To separate out the accounts into their own "ecosystems" within the same code base is called multi tenancy. Basically, you scope your applications queries based on the user id and/or role which limits the available data to any given user.
Have a look at the Landlord Package.
In a very basic summary, what it does is add a where('tenant_id, auth()->id()) clause to every applicable query.
You can of course either omit the clause entirely for super admins to access all data, or apply even tighter constraints, say by adding a check for the user's role in addition to the clause, further limiting what a user can access within their respective account/organization/group etc.
Scoping can be done by any kind of relationship, you're not necessarily limited to the authenticated user's id. If your application has organizations for multiple user's you can use the organization id.
Multiple tenant ids is also possible, where a user must belong to an organization and a certain division within that organization.
Another package I've used previously is Hyn's multi-tenant.
We have same project as you mention . We create a company table and put it on the top of the hierarchy.
Then add new field all tables as company_id
And manage models over Policy -> https://laravel.com/docs/5.8/authorization
I hope this help
The desired outcome would be that users can create account for company becoming first employee for that company having super-admin role. He then can create other employee accounts that have access to company account.
For that I have two models
Team (the company account)
User (the employee account)
and there is one-to-many relationship between team and user.
I have added global scope to User model in order to automatically load associated team so it would be easy to display necessary information in views.
The User model is authenticable.
Users can have different permissions. For example only super-admin is allowed to delete other user from team. I am following the Laravel way to authenticate action by using custom requests
public function destroy(DeleteTeamUserRequest $request, $id)
{
$this->users->deleteById($id);
return redirect()->route('dashboard')->withFlashSuccess('Deleted User');
}
class DeleteTeamUserRequest extends FormRequest
{
public function authorize()
{
return $this->user()->isSuperAdmin();
}
}
This way I can be sure that user without super-admin role wouldnt delete other user. However theoretically super-admin of company 1 is able to to delete user form company 2. Of course he would never have that url in frontend but if he tempers the code he has the permission to delete all users.
I could always check in controller that given user is within the team but thats just wrong.
I made both Users and Teams authenticable (create another web guard for team), manually log in the team once user logs in (the same on logout) but came upon the same problem - I have to check if user I try to delete is within the same team as user that performs the action.
{
public function authorize()
{
return $this->user()->isSuperAdmin()
&& $this->team()->has($otherUser); // I dont have other user here
}
}
The scenario should be quite common but I couldnt find a good explanation on how to properly handle these cases so I would highly appreciate any suggestions and help.
You can fetch the route param in the FormRequest like this:
$otherUserId = $this->route('id');
You can just fetch the other user and its team and compare that with the team of the authenticated user.
You can also write a little helper/service which can do the same; check if 2 users are part of the same team.
You're describing multi tenancy in your application. Many different users or groups of users having access to the same software but restricted to their data only.
Basically what you want is a team_id on the tables that have relationships to the team of a given user.
Typically, a middleware checks that a user belongs to a team and has the task of scoping queries for the duration of the request. For example, the middleware would add a where clause to every query made during the request lifecycle of the form ->where('team_id, auth()->user()->team->id).
This would prevent users with super admin roles from cross polluting or deleting other team's data because the where clause would not allow for it.
There a few really good packages that provide this functionality and then some. My personal favorite is Landlord.
So i have two models
clients
employees
The main difference between these two are that employees has some different more advanced controls.
Now regardless of what user that logs in i need to set a cookie (what the cookie does doesnt matter just to give you an idea).
Now since my employees has more options and actions than clients there is a seperate index view for the.
Now to my question since both types of users has to set a cookie is it possible to do this from the client login controller meaning that "unknown person tries to log in" -> "checks client model if user exists" if not "check employees controler if user exists" if true -> "set cookie " ->"go to employee view index"
Is this possible and is it a good way to do it. Note that the reason why i need to do this is because i want to create a God like user in the clients table. My client table consists of alot of joins and it would be easier to create a "God like" user that will look the same as a normal client (kind of like a proxy).
I think you’ve gone about this the wrong way.
Ideally, you should have a users table and a corresponding User model, and then use ACL to determine what a user can and can’t do. You can create roles for clients and employees, and set permissions on these groups, and assign each user to a group.
If you have client- and employee-specific data you wish to store, then you can always create these tables/models and set them to belong to a User.
I'm building a PHP application where users can design products and then check out to a shopping cart if they want to.
To let the user create a design, I need to assign a user ID and design ID to store it in the database.
There are two types of users who can build designs:
registed users. To take care of this, I have no problem.
non-registered users. These are guest visitors who might play around with product designs, and then when they hit check out, only then will I ask them to sign up. But in order to store their designs, I do need to have some kind of user ID.
I thought of using a timestamp as this user's ID, but what if two users in different parts of the world create designs at the same time? What's a good strategy for generating IDs for temporary/guest user accounts? I don't just mean temporary in the php session sense, because I want them to be able to access their partially saved designs later on if they visit the site again, just like any other registered user. I will only ask them to sign up before checking out for payment.
A simple approach might be:
Use a single user table (for registered users and guests)
Assign a "user_type" flag. E.g. registered/guest
Use the table primary key or other unique value for both "types" of user
When guests check out later on, switch their "user_type".
Store other related customer details in a separate table.