Let's say there some users who have several posts. Every user has many posts, and every post belongs to one user.
To change post frontend uses URL like users/1/posts/3. The goal is to check, that post number 3 belongs to user number 1.
There are several ways to do it:
Check inside controller method or service(bad method IMHO)
Check inside custom request (authorize function)
Check inside middleware
I choose between the last 2, but have some doubts. The custom request should contain validation rules and do not be linked with authorization(SOLID), and I don't know if it's good to do it inside middleware.
I assume you want to check if user can modify the post.
For authorizing access https://laravel.com/docs/7.x/authorization#creating-policies is a way to go.
After defining policy you can reuse it in blade files, in controller and etc..
The policy defines rules for standard actions like create, read, update, delete.
For blades then you can:
#can('update', $post)
For methods in controllers:
$this->authorize('update', $post)
For anywhere else:
$user->can('update', $post)
You can use Policies in conjunction with custom Form Requests
Related
I am so confused about how to implement and how to follow SRP (single responsibility principle ) in a Laravel controller.
Suppose we have a controller which we have to do these things:
e.g
public function StorePost() {
// check user login()
//check number of current user Post count =>which must be less than 10
//store post
//send an email to user which your post has saved
//return =>api:json /web : redirect
}
I know that I can implement some DB queries in the repository but I don't know how to implement others of my logic code to achieve SRP
Also, I know there is a Heyman package to achieve these but I want to implement it by myself.
SRP in this context basically means each class and method should only be responsible for a single behaviour/feature. A rule of thumb is a class or method should change for one reason only, if it changes for multiple reasons, it needs to be broken down into smaller parts.
Your storePost method should not bother with checking the user login, that should be handled elsewhere before invoking storePost. storePost shouldnt change if the auth mechanism changes like switching from api token to json web token or something else. Laravel does this in the middleware level with the auth middleware.
Checking the users post count, this can be checked in the validation stage. storePost shouldn't change if we add more validation logic. In Laravel you can use FormValidation for this
For storing the post, the controller doesn't need to know how to call the DB, you can use the active record style using the model class or maybe create a service or repository class if your use case requires that. storePost shouldn't change if we decide to change DB vendor like going NoSQL.
For sending email, again the controller doesnt need to know how to send the email like what the subject/body recipients are. storePost shouldnt change if we need to change the email layout. Laravel has Notification for that
For serialising the response to json, the controller doesnt need to know how to format the response. if we decide to update how our json looks, storePost shouldnt change. Laravel has API Resources for that
So, ultimately in this example, the responsibility of the controller method is basically to glue all these together. It basically does what you wrote down, it only responsible for maintaining the step by step behavior, everything else is delegated to someone else. if the behavior change, like adding new behavior e.g notify all follower, storePost will change.
I have a resource named Post. Every Post is related to a single User, and a User may have several (or zero) Posts.
I'm using Route::resource to map routes for every possible action on the Post resource to a single resource controller, PostController.
Now, I wish to implement a policy for the Post resource. Aiming to keep everything as simple and fool-proof as possible, I'd like to make the policy as follows:
Every user is authorized to make any action that doesn't require an existing Post (e.g. create).
A User is only authorized to access its own Posts for every action that accesses a Post (e.g. edit, update, delete).
What I'm trying to do right now is to create a single policy method called access, which would check that the Post is owned by the User. Then, in my PostController, every method that has a Post object in its parameters (such as edit(Post $post)) would begin with
$this->authorize('access', $post);
However, I don't like that I need to put those lines manually. If I ever forget one of those, I'll have a security hole right there.
On the other hand, I have the authorizeResource method, which makes authorization automatic but requires the policy to have several methods so they are mapped to the each of the controller's methods. Also, I tried to use the Authorize/can middleware, but it didn't work (maybe because I used it on a Route::resource mapping).
The question is: What would be the cleanest and more secure way to achieve the result I described (i.e. authorizing every possible action that accesses a resource with the exact same rule)?
You can use authorizeResource() and override the resourceAbilityMap() method in your controller. The latter method returns a mapping from controller methods to the policy methods that will be called.
https://github.com/laravel/framework/blob/5.7/src/Illuminate/Foundation/Auth/Access/AuthorizesRequests.php#L105
E.g.
class MyController extends Controller
{
// ...
/**
* Get the map of resource methods to ability names.
*
* #return array
*/
protected function resourceAbilityMap()
{
return [
'edit' => 'access',
'update' => 'access',
'destroy' => 'access',
];
}
// ...
}
I'm using this line in some controller's __construct
$this->middleware('auth');
This results, that every not logged user will be redirected to login page. It's of course, ok, but there is a problem.
I have two groups of users. In database I have a column called "role", which is boolean. 0 means basic users and 1 means admins. How can I treat, that entrance to some of controllers will be allowed only for admins? I really don't know how to do that in pretty way.
You can pass things to the middleware, like
$this->middleware('auth:1');
Now in the middleware you can check to see if the authenticated user has a role that you passed (in the example, 1). If they don't have the role that you require, then you can redirect them to the login screen or however you want to handle it.
you can use the following code to get the authenticated user and then write custom logic.
if(Auth::user()->role==0)
{
//you are basic user
}
esle if(Auth->user()->role==1)
{
//you are admin
}
you can also Gates and Policies for this type of work.
I have some trouble figuring out how to do this properly.
I have Users that can create Articles which can be viewed, edited and deleted. I want to restrict the edit and delete actions if the currently logged in user is not the creator of the Article.
I have already done this using Policies and use Gate within a Form Request, but if i understand correctly FormRequest is only for POST requests. And I currently pass the FormRequest as a parameter to the getEdit() action. That seems wrong.
So how can I make sure the user can neither access nor edit the Article?
If you already defined a Policy you can directly access it using the Gate facade within your controller action like this:
public function getEdit($id)
{
$reference = Reference::findOrFail($id);
if (Gate::denies('owns-reference', $reference))
abort(403);
return view('reference.edit')
->with('reference', $reference);
}
Just make sure to include the Gate on top of your file like this:
use Gate;
I want to separate my cakephp application in users authentications... I have created authentication key of 50 digits as boolean. that is 10111... in this way.. Now I wanna separate my application accordingly. Suppose for blog post. I want to access to view post if users first authentication digit is 1, If my post is private then I need to authenticate it using digit 2. For any other status of my post suppose private I wanna again check an action of digit. What should I do with this scope.? Is it better way to go with...
Second I want to have common function. I have just taken example of simple controller post I wanna do it for most of my models and controllers. How can I make single inbuilt function for all.
You'll need to create all these rules in your AppControllers Authorize() method, assuming you are using the AuthComponent and Controller as your auth method.