Controller Authorization not working in laravel 5.2 - laravel-5

I want to authorize my delete action using the Controller Authorization. Instead of using DELETE, I am sending the delete directly to the controller. Student can be deleted by instructor.
I followed the approach as explained at -
Controller Authorization
Below is my function -
public function deleteProfile(Student $student)
{
//authorize the request
$this->authorize('deleteProfile',$student); //$student is valid Student object
$student->delete();
}
When I try to delete it gives me exception -
HttpException in Handler.php line 104: This action is unauthorized.
I found this approach simple so, tried to implement it. Is there anything which I am missing ?

Correct this file with your xxxPolicy.php
Add the intval() in case. And it`s work.
ProjectPolicy.php :
public function destroy(User $user, Project $project)
{
return $user->id === intval($project->user_id;
}

Register a gate policy where you put the logic of who can delete the request. If by that logic the current user can delete, it will be deleted else it will throw a not authorized exception like you did.
Or else you can manually give authorization on your controller method for the user
$this->authorizeForUser($user, 'deleteProfile',$student);

as per documentation "The Gate will automatically return false for all abilities when there is not an authenticated user". So before doing any authorization, please check Auth::user() if it returns a currently authenticated user."

Related

Do I get a 422 HTTP code even though I am logged in?

Do I get a 422 HTTP code even though I am logged in?
From my blade I send an XHR post request. In the route I use the auth middleware. This works. This means you have to be logged in to send the post.
web.php
Route::post('/posts', [PostController::class, 'store'])->middleware(['web', 'auth'])->name('posts.store');
Now I created my own request class to validate the sent data.
PostStoreRequest authorise method
public function authorize()
{
return false;
}
Since I use my own custom request class I get this error message even though I am logged in:
This action is unauthorized.", exception: "Symfony\\Component\\\HttpKernel\\Exception\\AccessDeniedHttpException
I wonder why this is?
You have to check in the authorize() method if the user is authorised for this action. If you have a role system right you can implement this here. For example, only users with the Writer role are allowed to create a post. If you don't have that and you just allow everyone who is logged in, then change the return to true or return auth()->check().
Example without role system:
public function authorize()
{
return true;
// or
return auth()->check();
}
With role System:
public function authorize()
{
return auth()->user()?->isWriter();
}
Important Note: Thank to #matiaslauriti && #Tpojka for the right advice / good review.

how to check if user is authenticated with passport (get user from token using laravel-passport)

I am using Passport to log in users to a Laravel API endpoint, users get authenticated using their social accounts (google, facebook) using laravel-socialite package.
the workflow of logging users in and out works perfectly (generating tokens...Etc). The problem is I have a controller that should return data based on whether there is a user logged in or not.
I do intercept the Bearer token from the HTTP request but I couldn't get the user using the token (I would use DB facade to select the user based on the token but I am actually looking whether there is a more clean way already implemented in Passport)
I also don't want to use auth:api middleware as the controller should work and return data even if no user is logged in.
this is the api route:
Route::get("/articles/{tag?}", "ArticleController#get_tagged");
this is the logic I want the controller to have
public function get_tagged($tag = "", Request $request)
{
if ($request->header("Authorization"))
// return data related to the user
else
// return general data
}
Assuming that you set your api guard to passport, you can simply call if (Auth::guard('api')->check()) to check for an authenticated user:
public function get_tagged($tag = "", Request $request)
{
if (Auth::guard('api')->check()) {
// Here you have access to $request->user() method that
// contains the model of the currently authenticated user.
//
// Note that this method should only work if you call it
// after an Auth::check(), because the user is set in the
// request object by the auth component after a successful
// authentication check/retrival
return response()->json($request->user());
}
// alternative method
if (($user = Auth::user()) !== null) {
// Here you have your authenticated user model
return response()->json($user);
}
// return general data
return response('Unauthenticated user');
}
This would trigger the Laravel authentication checks in the same way as auth:api guard, but won't redirect the user away. In fact, the redirection is done by the Authenticate middleware (stored in vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php) upon the failure of the authentication checking.
Beware that if you don't specify the guard to use, Laravel will use the default guard setting in the config/auth.php file (usually set to web on a fresh Laravel installation).
If you prefer to stick with the Auth facade/class you can as well use Auth::guard('api')->user() instead or the request object.
thanks to #mdexp answer
In my case I can resolve my problem with using
if (Auth::guard('api')->check()) {
$user = Auth::guard('api')->user();
}
In my controller.

Laravel Policy with Spatie Permission check gives 403 for client credentials API request

I'm using Laravel Policy and checking for permissions created using Spatie's Laravel-Permissions package.
For an API call with client credentials, the authorizeResource() in the Controller constructor returns 403. If this is removed, it returns the expected results.
NpoPolicy.php
public function view(User $user, Npo $npo)
{
return $user->can('npo.view');
}
NpoController.php
public function __construct()
{
$this->authorizeResource(Npo::class);
}
api.php
Route::middleware('client')->resource('/npo', 'NpoController');
API Request
URL: https://my-app.dev/api/npo/1
Method: GET
When I comment out the authorizeResource method in the controller constructor, I get the result as expected:
{
"npos": {
"id":1,
"name":"Bailey and Sons",
"contact_person_name":"Mr. Davion Mayert",
"created_at":"2019-06-13 17:39:25",
"updated_at":"2019-06-13 17:39:25"
}
}
I'm aware that a Laravel policy requires a User model object and that is why the policy is returning 403 response in my case. Is there a general practice to handle API requests (with client credentials) in these cases?
You have missed the second parameter at authorizeResource function so, at the NpoController.php change the authorizeResource to:
$this->authorizeResource(Npo::class, 'npo');

Authorization from model

I have a Board.php model with a method checkViewAccess()
i.e
#if($board->checkViewAccess())
render board
#endif
It does a few checks, and on the last check it needs to call a policy method to determine authorization for the user.
In blade, #can('view', $board) works
In controllers, $this->authorize('view', $board) works
But I cannot for the life of me find out any way to call a policy authorization from the Board model
What I've tried:
Gate::check('view', $this) // Non-static method, which is fine, didn't expect it to work
auth()->user()->can('view', $this) // This doesn't even hit the policy and returns false regardless of what I return from the policy. Even if I just return true in the before() policy method it's false. Laravel docs claim the can() method is avaiable on the user object
$user->can('view', $this); // Thinking it was an issue with the auth facade, I fetched the user directly from the database and it still didn't hit the policy
So how can I achieve this? How can I access laravels authorization from a model?
Turns out it was the Laratrust package which uses the can() method in a trait, so I can't add my own Authorizable trait to my user model
Fix:
use LaratrustUserTrait;
use Authorizable {
LaratrustUserTrait::can insteadof Authorizable;
Authorizable::can as authorize;
}

laravel 4.2. user permissions and hiding link source

I am a total newbie with Laravel and learning it now for a week. I have some basic questions that I can't find an answer to. Next week I will start with developing CRM system and I need some info from experienced developers who could tell me is the approach I am attending to make a good one.
I will need some authentication system, like 4 groups of users (Admin, Basic, Manager, Office) where Manager and Admin will add the Basic users. There will be few view and features and every groups will have defined access to each view and feature. Since few days I am searching for packages, watching the tutorials and learning. I found an interesting package for which I think it could help me with this user-group-permission things.The package is Sentry. Could this help me with my requirements?
What is the case when for example I have a user in group Basic and he deletes for example some comment with the button. On the left side down in the browser the user can see the link to this comment when he hovers the link. For example www.test.com/comments/345/delete where the id is 345. What if user types that with another id, that means he can delete another comment. I found some suggestions on how to solve this, to make it with jQuery and javascript so the link wouldn't be shown and POST would be made with for example with AJAX. But since I am a newbie, I am thinking how much time would this take and is this a good approach at all? Could package Sentry from 1. question help me with the permission on what route each group can access?
Any help or advice would be appreciated.
Sentry does what you want, yes. Here's a question with some answers explaining the permissions part.
The visible link part can be avoided by doing a POST request instead of a GET request.
When you open your form, you add a method attribute.
Form::open(array('url' => 'foo/bar', 'method' => 'post'))
A GET request will put the parameters in the URL, hence the visible ID. Using a POST request will put the parameters in the headers, thus hiding it from the URL.
An example could be deleting a comment. A GET request could look like this:
http://www.example.com/comments/delete/1
And the parameters would be defined in your method signature:
public function getDelete ($id) {
Comment::find($id)->delete();
}
Where the POST equivalent would be
http://www.example.com/comments/delete
And the parameters would be defined in your Input class, you would get them using the get method
public function postDelete() {
Comment::find(Input::get('id'))->delete();
}
1) The best package to help you with that is Sentry indeed.
2) To make sure an user can delete only his comments you can do something like this (but there are more solutions either you do it with Ajax or not):
public function destroy($id) {
$user = Sentry::getUser();
$comment = Comment::find($id);
if($comment) {
if($comment->user_id != $user->id) {
return Response::back(); // optional message: Permission denied!
}
$comment->delete();
return Response::back(); // optional with message: Deleted!
}
return Response::back(); // optional message: Comment not found!
}
You can use Sentry in this case to get the logged in user and check for user id. I think you should let user delete their own comments always but if you need special roles (Admins for example) to be able to delete any comment, or special permission comments.delete (For some Managers) - you can use Sentry as well:
public function destroy($id) {
$user = Sentry::getUser();
$comment = Comment::find($id);
if($comment) {
if($comment->user_id != $user->id && !$user->hasRole('Admin') && !$user->hasPermission('comments.delete'))) {
return Response::back(); // optional message: Permission denied!
}
$comment->delete();
return Response::back(); // optional with message: Deleted!
}
return Response::back(); // optional message: Comment not found!
}
A nicer way of making the DELETE thru a Form request check this:
Laravel RESTfull deleting

Resources