I'm having a bit of trouble understanding the proper times to use ACL or middleware in Laravel. I do understand the examples on their site and Laracasts, but they're rather simple examples.
This isn't anymore complicated by any means, but I didn't see examples for these. Let's say I have two routes that allow a user to create a task. The first being the GET request to fill out the information, and the second being the POST to store the information. There are some users that are not allowed to create tasks based on their role. In both cases, there isn't a particular object that exists, which is what the ACL requires as far as I understand. So would I use middleware for something like that? And when an object exists, use ACL for that?
An alternative I've been trying to fit in is the use of Form Requests too, but then I'd have to create a Form Request object for each route (although I don't really mind personally).
What is a good approach to limiting acccess to actions, when there isn't a specific action to act upon?
Thanks in advance.
Notice: I was going to post this as a comment, but it got a little too extent. Feel free to wait for better answers and maybe consider this just a comment.
I think that you're missing the whole point here. You can have a middleware that consults the ACL or you can use the FormRequest to consult the ACL or use each of them separately. For instance, at the authorize method of the CreateTaskRequest, you can check the ACL to see if the user has the proper role to create a task.
You might be getting too hooked up when Jeff tries to check if the user owns the post. That kind of ACL is record-oriented, but you can have a role that just takes the user as a parameter (and no other entity) and see if that user just has a specific role. By returning true, the action is authorized, otherwise it's denied.
A middleware have more to do with the route instead of the request. You can also have a middleware that gets the authenticated user and check if it has the role to create a task. Those are different ways to achieve the same thing (which is one of the benefits of Laravel, having lots of ways to achieve the same goal).
Your specific action to act upon is the "Create new Task" action. Who do you want to be able to do that? Users that have the role manager? Users that have the permission create-task?
At the end of the day, what I would consider is:
Are there lots of routes that will have the same rule? Maybe a middleware would be a good choice.
Are there specific rules for each kind of operation? Can an user that did not create a task be able to edit one? Form Requests might be easier to achieve this kind of specification
Which $this environment would make my life easier? $this from the Form Request or $this from a middleware?
One thing I learned from Jeff's class are that he teaches too much cool stuff and sometimes I end up missing one point or two. Try re-watching the basic steps again and maybe stop when you think you found something that would work. Then implement that and see what your case differs from his and how you think he'd write that feature.
Related
Okay, so I know about middleware hence the "From Controller" specification in the title but basically, the issue I have is this, I have a SaaS app that I'm adding a gifting feature i.e give someone a plan as a gift and so I need to force login on a regular user while allowing either way on one gifting the plan to make it easier. Makes sense? Anyway, for that reason, I cannot use the auth middleware since I have, and want, only 1 checkout page.
So, how can I force login from my Checkout Controller like the way the auth middleware does it on routes?
Since I haven't gotten a suggestion, I'll post the workaround I came up with and the potential solution I simply have no time to study up on at present:
Likely solution:
Use Auth::guard('guard name here') and you can learn more about this here.
My workaround:
I created another route pointing to the same controller function but one is going through middleware('auth') while the other isn't. Practical example below.
Route::get('checkout/summary', [CheckoutController::class, 'summary'])->middleware('auth')->name('summary');
Route::get('checkout/gift-a-sub', [CheckoutController::class, 'summary'])->name('gift-a-sub');
With this, I only require one page to prevent complications while forcing authentication for regular users while those just opting to gift a plan aren't required to do so and all I have to do then is save the data based on a flag created at the Pricing page.
If I have two routes:
Route::get('/setup', 'SetupController#index')
Route::post('/setup' 'SetupController#store')
In the SetupController#index I do some checks, for example I check if the user is authentificated. But there are some more rules there that I check.
Should I perform the same checks on the post route too?
Is there any way someone could hit that post route without hitting the get route first? (for example posting in url http://domain/setup?password=1234)
So I guess what I am asking is :
Do I need to wrap the two routes in a middleware and do checks on each of them or is enough to check on the get route?
yes you need to wrap both routes in the middleware.
someone can open anypage (login for example) and edit the html to make a form that point to /setup and put whatever he wants in it.
sure, that someone need to know the architecture of the form to do this, but it's a risk nonetheless.
Normally, you need to add corresponding middlewares for different urls, for the get route, you can use ReplayAttackMiddleware for unnecessary attacks; and for the post route, I think you need to add different roles for different users, and JWT is a really good tool for authentication.
Before you read the title and vote as duplicate, hear me out. I haven't been able to find another example of what I am after.
I have a Laravel 5.5 application that uses the built in Laravel Auth class for user management.
If a user tries to perform an action I want to stop/allow the action based on the user's level.
I have gone through the docs and found that I can write my own custom validation rules by implementing the \Illuminate\Contracts\Validation\Rule interface and call it in the controller but I want to, basically, pass the validator the user level and the level required and validate from that.
Can someone please point me in the right direction to do so?
I dont think the form validation is the best way to make what you want. If you want to restrict actions depending on user permission (here level), you have to create the levels and then check for it before try to validate the form.
I recommend you tu use the Authorization part of Laravel which is well explained in the doc
Where should the authorization code in Laravel? We have a lot of options and a lot of plugins to manage this situation but and I'm not really sure where I should put all logic. Let's see:
I know that there are a lot of possibilities with a correct result but I want to know which is the optimal solution for you or know your techniques in this situations.
Imagine we have a help desk application done in vuejs and Laravel as API, so we have users, groups, roles, permissions. And maybe a user will only able to see its tickets.
Should we do a TicketPolicy with view, update, create methods? Maybe should we use repositories? Maybe a is_user_allowed method in Ticket's model?
Should we use middleware in routes files and do something like Route::get('tickets/{ticket}', 'TicketsController#show')->middleware('can:show')? Or should we call $this->authorize($ticket) in show, edit, update and store methods of the controller?
Or maybe should we use FormRequest#authorize method and then use something like $user->authorize('show', $ticket)?
What if we want groups or roles? Should we use some plugin like Entrust and/or policies?
What do you think, what do you do?
Best place I found to put classes that group specific logic that do not fit in standard MVC pattern is completely new folder for Laravel. I name mine Services, probably because I read it somewhere. One of the great things in Laravel (and probably other modern frameworks) is flexibility, you can just pop a folder, add a new namespace and have it contain whatever you need.
As for your example, I would implement a class App\Services\Permissions that would contain all necessary logic for accessing different resources in your application. Then call it's methods wherever you need them, be it Requests, Middlewares or Eloquent Models.
I'm working with a Joomla site, whose index.php file has been modified to alter the default access control behaviour. Bearing in mind this is Joomla 1.5, this line:
$mainframe->authorize($Itemid);
has been wrapped in some conditional code that looks up the remote IP and doesn't call authorize() if the IP is within a whitelisted range [*]. This is to allow seamless access to certain resources without logging in.
Although I'm new to Joomla development, I'm guessing this isn't the best way of doing that. For one, it probably means re-patching index.php in the event of a future Joomla upgrade. What's the best alternative approach to intercepting the authentication check?
[*] This is another mystery: the IP management takes place on the front-end via a component called 'IP filters'. There's a totally empty directory at components/com_ipfilter, but a more featureful-looking one at administrator/components/com_ipfilter. The component stores data in a table named kip_filters (why the 'k'?) and the authorUrl listed in the component's manifest file goes to a spammy-looking like pharma page. All quite worrying ...
What you are looking for is a system plugin which would not require hacking any files. There are quite a few system events that you can use to trigger your plugin and do your IP test, then determine whether to continue displaying the page or redirecting the visitor to some sort of warning page.
Take a look at the documentation on system events - http://docs.joomla.org/Plugin/Events/System
--- More detail ---
Looking at the API execution order, the call to authorize() is going to happen no matter what (http://docs.joomla.org/API_Execution_Order). Since the default behavior is to call authorize() you are going to have to trick it into returning a positive response.
Your plugin should be triggered by onAfterInitialise and you should manipulate JUser. When you call authorize() the functions needs a user id which it gets from the JUser object and the getuser() function. All you need to do is create a user with the permissions you want, then have the plugin set the user ID so that authorize() returns true.
For the security problems you can use these steps and i will give you a good ip filter component as well :
First of all this is the most important component you can have for joomla :
http://extensions.joomla.org/extensions/access-a-security/site-security/site-protection/16363
it gives you the most important ways to avoid any hacking or spamming or php bugs and also provide a very fast upgrade for your joomla site :) also it offering a IP Blacklisting manager which is a complete solution for your problem.
Hope this post will give someone a light !
Regards,
Raeed Rabie
I'd advise changing your table prefix from jos_ to something random, like hsfdaghadfg_
You can also relocate your configuration file for extra security.