Scenario
Im building an application that offers 3 levels of paid services but im not sure how to go about coding the 3 level functionality.
So for example if my app allowed users to post content to a page, and the 3 levels allowed you to post 1,5 and 10 times a month would i just set up a database that stores the data and then create Middleware to check the amount of times posted / the users post level etc. Im just not 100% certain im going about this right and was wondering if laravel offered any alternatives that i may have overlooked.
Question
Should I use middleware to control user levels or does laravel offer alternative and more specific methods?
Consider implementing user roles which correspond to each membership level (i.e. the first role could be 'basic user', the second role could be 'intermediate user', and the third role could be 'advanced user') if you don't want to go with the suggested policies route. Roles can be set up in Laravel using existing packages such as Entrust and Sentinel. In your users table, you should have a user name and role id (foreign key to a role), in your posts table you should have a user id (foreign key to a user) for each post and in your roles table store a post limit against each role (or store it somewhere in the application as a constant/config). When a user attempts to create a new post, you can do a count of all posts they've already submitted, e.g.
App\User::findById(1)->posts->count();
or consider using withCount() if you don't want to actually load them. Then follow this up with a check for how many posts the user is limited to, e.g.
User::findById(1)->role->postLimit
A comparison between the two should allow you to determine whether or not the user is able to continue posting.
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
I am quite new to Laravel, but get most of the basics by now.
Currently, I build an application, where multiple companies each get an account that represents their main user, let's call him CompanyAdmin.
This user is allowed to create new users for this company and able to view all quotes from the company.
The newly created users, call them CompanyEmployee, can not create new users and only view the quotes they created themselves, as well as creating new quotes.
Now there is of course one SuperAdmin, which sits on the other side of the table. He views all quotes from all companies, is able to do create users as he pleases and can accept/edit quotes.
My current approach to do this would be to attach a user_id to all quotes and attach the users to a company, as well as giving them a role.
All the logic would take place in the controller, where I would check the role of the user and therefore read/save only the quotes, the user is able to edit.
However, it feels very dirty to do so and sounds like a lot of effort to maintain. If you would e.g. make another role for an employee of the SuperAdmin, you would need to change every controller.
I could not find a way to define the access rights per role per model, so when I call Quotes::all() it only retrieves the legal ones (same goes for saving of course).
Please guide me to a Laravel feature (or even package, but I have not used one before) that helps me get things done.
Looking forward to possible solutions that lead to low maintainance.
Best regards!
For authenticating different types of users and protecting group of routes that particular type can access you can use guards, for authorizing CRUD actions you can use FormRequest, I think you have everything you need under these 2 links, ofcourse you will need to read up on these, this is a good starting point. As for tables, you can have these:
users, roles, companies, user_role, user_company
And models:
User, Role, Company
from the doc
In addition to providing authentication services out of the box,
Laravel also provides a simple way to authorize user actions against a
given resource. Like authentication, Laravel's approach to
authorization is simple, and there are two primary ways of authorizing
actions: gates and policies.
Laravel has 2 concepts called Gates and Policies which we can inject it on models,(specially Gates), So when ever the queries are called upon the Model, the Gates make sure that the user has appropriate permissions.
You can read more here
In Laravel what is the best way to associate a user with every CRUD action?
Every user is created with a company_id field. When they view data such as a blog they can only see blog posts that were created by users with the same company_id. Also when they add a blog post it uses their company_id when saving the blog post, which is simply. But what if you have a common url schema website.com/blog/40 if a users types that it they can only access if their logged in with the same company_id.
I know the basic solution is to add the $this->user->company_id if every call to the db but that seems to be very repetitive. Is there a way to add it to the model? So that every time I make a request to the db it goes through the model to verify if this user has the access to view, add, edit, delete the data. Also if there is a blog post would I have to have a company_id column in the blogs db table or can there just be a user_id column and then the table associates itself to the users table and grabs the company_id that way?
In addition this laravel app isn't just a blog, it is going to a have many controllers and features so I want this type of security access tied to every element of the site down to each user.
Laravel has already packages for that, take a look at 'Laravel Auditing'.
http://www.laravel-auditing.com/docs/4.0
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.