I have been having problems with my site in Laravel for some time. I have an Angular frontend and I'm using an api to query the specific user's data so that a specific user can change his data in his profile page. With that said, I obviously don't want unauthorized people to be able to go to other profile pages to change their data as well.
For example:
On my page, with the URL .../user/1
the user can query his data. The problem with this is: If you change the 1
in .../user/1
to .../user/2
for example, the person can access to the data of the person with id 2
.
I tried following:
In my api.php
:
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
// Get Specific User
Route::get('user/{id}' ,'App\Http\Controllers\UserController@getUserById')->middleware('auth');
Unauthorized users can no longer access the profile page, but all Authorized users can access all other users and change their data.
I also tried: $id = Auth::id()
, but this returns me Attempt to read property "id" on null
The problem seems to me to be quite complicated, as I somehow need the id of the users currently logged in and make sure they can't access other users id. Do you have any idea how I could best do this?
I am using Laravel 8
Thanks a lot!
EDIT
Thank you for the detailed answer, you gave me hope. I did everything as you described.
First I created with php artisan make:middleware ResourceOwner
middleware and initialized it in the Kernel.php
under protected $routeMiddleware like that:'ResourceOwner' => \App\Http\Middleware\ResourceOwner::class,
and put in the function like you described.
But unfortunately, I get now 401 (Unauthorized) no matters what ID I pass and with which user I am logged in. I tried:
1. auth('api')->user();
2. $request->user('api');
3. Auth::guard('api')->user()
But nothing of them worked. Do you have any idea what I am missing? I also noticed that when I delete the function you described:
public function handle($request, Closure $next)
{
if ($request->id !== auth('api')->user->id) {
abort(403);
}
return $next($request);
}
I still get the same error 401 (Unauthorized).
But when I encode my JWT, I pass user_id as the ID, does that have anything to do with it?
But in my database my user is declared as id like: $table->id();
. Unfortunately, I am still too inexperienced to say if this could have something to do with the error message. I use the Tymon/jwt-auth package.
Thanks again a lot for your time and effort, I really appreciate it.
IMO, you should use /users
routes in regards to users' CRUD and a /profile
route for editing the user's data.
Anyway, there is a simple way to achieve what you need with middlewares.
Let's say that you want to allow to use a route ONLY if the {id}
parameter is the same as the authenticated user.
You can create a very basic middleware IE ResourceOwner
<?php
namespace App\Http\Middleware;
use Closure;
class ResourceOwner
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$user = auth()->user();
if ($request->id != $user->id) {
abort(403);
}
return $next($request);
}
}
The middleware will check if the incoming id
parameter is the same as the user logged in, if not, abort throwing a 403
error response.
In order to use this middleware, you can add it to your route
use App\Http\Middleware\ResourceOwner;
Route::get('user/{id}' ,'App\Http\Controllers\UserController@getUserById')->middleware(['auth:api', ResourceOwner::class]);