Cant get Auth::user() inside resource - laravel

I'm trying to get Auth::user() inside resource, but it returns null.
public function toArray($request)
{
return [
'test' => Auth::user(),
];
}

Please be more precise. Is this resource inside the api.php or inside the web.php? It is important since API is stateless; it is normal to return null if you are trying to access the user inside a route from the api.php and if you are not assigning the auth:api middleware to that route.
If the resource is inside the api.php, it should look like this:
Route::get('/something', 'Api\SomethingController#toArray')->middleware('auth:api');
Otherwise, if it's in web.php and you still don't get the user, try to inspect the browser cookies/sessions and make sure that after you're logged you see that in the storage.

Related

$request-merge() disappears in parent controller

I'm stuck on a weird issue...
I have a simple middleware.
$request->merge([
'user' => $jwt->toArray(),
'app_version' => $request->header('app-version')
]);
When I do a dump right before the $next($request); the it has the user object and the app_version. All good! See image below:
Moving to the controller. When in the function of defined in the route, and doing a dump($request); it has the user Object
The InstallController extends the controller.php which extends the use Illuminate\Routing\Controller as BaseController;
In the controller.php we have a construct function.
For some reason here the $request is empty and lost the object.
Why is this happening? And why is this available in the InstallController but not in the parent?
What turned out is the following. In Laravel lumen, controller constructors are called after the middleware has completed the request. In Laravel the constructors are called before the middleware.
Meaning that adding params to the request in the middleware in Laravel doesn't work.
Thanks for pointing me in the right direction.

Laravel preventing user from accessing other users resource **url

I am passing a specific resource in the url, for ex.
https://www.example.com/{companyID}
And in the controller I can access the resource by
public function index($companyID)
{
// Code Here
}
I need to block users from changing the url and accessing other companyIDs from the system. Currently its open and is a security risk. I checked out Laravel Gate and Policy's but fail to see how this could be implemented for my case.
What I am really looking for is something in the AuthServiceProvider boot method that can check if the user really is the owner of the resource before continuing with the code.
Any help?
As mentioned before, you can do that by creating a Middleware that checks if your resource should be available to the logged in user.
See some details about middleware here
First, create a Middleware via php artisan, like this
php artisan make:middleware AuthResource
Next, add it to your App\Http\Kernel.php
protected $routeMiddleware = [
...
'AuthResource' => \App\Http\Middleware\AuthResource::class,
];
In your routes, you can now do the following:
Route::get('{companyID}', ['uses' => CompanyController#index, 'middleware' => 'AuthResource']);
That way, your AuthResource middleware is used whenenver the route is called.
In your App\Http\Middleware\AuthResource.php you have to change the code from
public function handle($request, Closure $next)
{
return $next($request);
}
to something that checks if the resource is available to the currently logged in user.
I assume that your companies table has a field user_id, which links the Company to a User. If your data structure is different, you need to change the code accordingly.
public function handle($request, Closure $next)
{
if ($request->route('companyID')) {
$company = Company::find($request->route('companyID'));
if ($company && $company->user_id != auth()->user()->id) {
return redirect('/');
}
}
return $next($request);
}
That way we check if the a route parameter with the name companyID exists, and if it does we check if it is available to the currently logged in user. If no companyID parameter is available, the page can be loaded without any restrictions.
That way you can copy/paste the code within the middleware for any parameters so that the middleware does work for multiple resources (not only companies).
This is can be done easily by middleware. But I’ll do this in more understandable way.
I assume that your user has one to one relationship with company.
So first create the relationship,
In your User model,
Public function company() {
return $this->hasOne(‘App\Company’);
}
Company model
Public function user(){
return $this->belongsTo(‘App\User’);
}
So, now make Authenticate by running php artisan make:auth . more details on Authenticate
And now in your controller,
public function index($companyID)
{
$current_user = Auth::user();
$user_company = $current_user->company; // get the current user's company details
If($companyID == $user_company->id){
// do something
}
}

Laravel using user id in route

So I have a route profile/{user_id}
How do I redirect user to that URL when they click on link?
Here's my controller:
{
function checkid($user_id) {
if (Auth::check())
{
$user_id = Auth::id();
return view('profile', [
'id' => $user_id
]);
}
}
}
Bit confused with the question but Laravel uses ID as default for dependency injection and changing it is easy: just change the routeKey in the model BUT in your instance, you're using the signed in user. So forgot the id!
<?php
namespace App\Http\Controllers;
class RandomController extends Controller {
public function index()
{
return view('profile');//use auth facade in blade.
}
}
In your routes use a middleware to prevent none authenticated users from reaching this method
<?php
Route::group('/loggedin', [
'middleware' => 'auth',
], function() {
Route::get('/profile', 'RandomController#index')->name('profile.index');
});
Now to redirect in your blade file use the route function, don't forget to clear your cache if you've cached your routes!
<h1>Hi! {{Auth::user()->name}}</h1>
View profile
Because I used the name method on the Route I can pass that route name into the route function. Using php artisan route:list will list all your route parameters which is cool because it will also tell you the names and middlewares etc.
if I had a route which required a parameter; the route function accepts an array of params as the second parameter. route('profile.index', ['I_am_a_fake_param' => $user->id,]).
Let me know if you need help with anything else.
You can redirect with the redirect() helper method like this:
return redirect()->url('/profile/' . $user_id);
But I'm not really following your usecase? Why do you want to redirect? Do you always want the user to go to their own profile? Because right now you are using the id from the authenticated user, so the user_id parameter is pretty much useless.

Passing two models to the Authorize middleware (also called can)

I am trying to pass two models to the Authorize middleware, used under the name can.
routes/api.php
Route::middleware('can:reach,profile,photo')->resource('users/{user}/profiles/{profile}/photos', 'PhotoController');
Then I try to retrieve arguments like so:
app/Policies/PhotoPolicy.php
public function reach(User $user, Profile $profile, Photo $photo)
{
return $profile->id === $photo->profile->id;
}
But the middleware is totally ignored. I checked the definition of the middleware and I cannot see why this would not work.
Thanks in advance.
I think you have to add the middleware to the resource, not the opposite. Or, you can create a group.
Example:
Route::group(['middleware' => 'can:reach,profile,photo'], function($router){
$router->resource('users/{user}/profiles/{profile}/photos', 'PhotoController');
});

How to have a route for both authenticated users and non-authenticated users

I have an issue with auth:api middleware!
We have a request that is accessible for both authenticated users and non-authenticated users when I define a route like this for non-authenticated users:
Route::post('{user}/leads', 'UsersController#getContact');
It's ok everything work fine when a guest user requesting this route.
is and I can access user with $request->user();
but if pass token with bearer header and get the user with $request->user() of course it doesn't work! because we didn't use auth:api on this route, and if we do we can't access this route with guest users!
So I can't find a way that we define one route for both authenticated users that if user is authenticated we get $request->user() and none authenticated users can access that route too!
Thanks in advance.
I found a way to do that I just wrote this:
$middleware = ['api'];
if (\Request::header('Authorization'))
$middleware = array_merge(['auth:api']);
Route::group(['prefix' => 'v1', 'namespace' => 'Api', 'middleware' => $middleware], function () {
//routes here
});
In api.php route file and it works fine.
Thanks
This is because Auth uses the default web guard. You have to check the api guard manually:
$user = Auth::user() ?? Auth::guard("api")->user();
Then you don't use any auth middleware. $user will be null if the user is a guest, otherwise it should be set.
The solution I used was to create a new middleware for auth:
public function handle($request, Closure $next, ...$guards)
{
try
{
$this->authenticate($request, $guards);
}
catch(AuthenticationException $ex)
{
}
return $next($request);
}
and in at the BOTTOM of my route I did:
Route::middleware('auth_optional:api')->group(function () {
Route::get('services', [ServiceController::class,'index']);
});
This way if Auth was needed ,it would assign the correct user to request, otherwise it would proceed as guest. I did need to do a $request->user() === null to make sure the user is guest
If you want the routes are visible to only Authenticate users you can put all routes in auth middleware that is default provided by laravel you can put like this:-
enter code here
Route::group(['middleware' => ['auth']], function () {
Route::post('{user}/leads', 'UsersController#getContact');
});
And if you want to show the route both authenticate and non-authenticate user
You can simply put outside the middleware
Lik that:-
Route::match(['get', 'post'], '/cms-page','CmsController#cms');
Hope you understand
I would like to use additional routes both authenticated and non-authenticated users,
But regarding the topic I add one simple way :
On the __constructor function of the Controller add those lines :
$authorizationHeader = \request()->header('Authorization');
if(isset($authorizationHeader)) {
$this->middleware('auth:api');
}
But I don't concentrate this way as best practice, this brokes Single Responsibility Principle.
If you are using Laravel Passport then this way can be more cleaner.
In controller you can directly get user by
$user = $request->user('api');
This will get you the authenticated user and if bearer token is invalid then it will not throw 'unauthenticated' error but result in null user.
Reference: How to authenticate user without auth:api middleware in laravel 5.3?

Resources