Get null when running JWTAuth::user() in Laravel - laravel

I've been using JWT for authentication in Laravel. I have a JWTMiddleware to check authorization, which works fine, like the following.
try {
JWTAuth::parseToken()->authenticate();
} catch (Exception $e) {
return response()->json(['error' => 'Token is Invalid']);
}
User model
class User extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
public static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->uuid = Str::uuid()->toString();
});
static::saving(function ($model) {
$original_uuid = $model->getOriginal('uuid');
if ($original_uuid !== $model->uuid) {
$model->uuid = $original_uuid;
}
});
}
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
}
Now I have a route that uses this middleware and returns an authenticated user.
Route::middleware(['jwt.verify'])->group(function () {
Route::post('/user', function () {
$user = JWTAuth::user();
return response()->json($user);
});
});
After entering this route, I get null. Why does the middleware work fine, yet I can not retrieve the user?

Related

Laravel 7: custom guard authentication does not work as expected

I have a multiauth project. I have the default authentication and a custom guard. At the login controller, when I make the login attempt, it authenticates as expected. However, when it gets to the homepage, the custom guard is not logged in anymore.
Users that use the custom guard already log in through an external API, so i don't want them on my users table. I just need a couple of fields to show them some content.
LoginController.php (Up to the return, attempt method returns TRUE)
...irrelevant code...
Auth::guard('ivao')->attempt(array('vid' => $user_array->vid, 'name' => $user_array->name, 'surname' => $user_array->surname), true);
Cookie::queue(Cookie::forever($this->cookie_name, $_COOKIE['ivao_token']));
Cookie::queue(Cookie::forever('vid', $user_array->vid));
return redirect('/');
...irrelevant code...
CustomProvider.php
class CustomUserProvider extends ServiceProvider implements UserProvider
{
public function retrieveById($identifier)
{
}
public function retrieveByToken($identifier, $token)
{
if(Cookie::get('rememberToken') == $token)
{
$user = new ApiUser();
$user->vid = Cookie::get('vid');
$user->name = Cookie::get('name');
$user->surname = Cookie::get('surname');
return $user;
}
else return NULL;
}
public function updateRememberToken(UserContract $user, $token)
{
if(Cookie::get('rememberToken') == $token)
{
Cookie::queue(Cookie::forever('vid', $user->vid));
Cookie::queue(Cookie::forever('name', $user->name));
Cookie::queue(Cookie::forever('surname', $user->surname));
Cookie::queue(Cookie::forever('rememberToken'), $token);
return TRUE;
}
else return FALSE;
}
public function retrieveByCredentials(array $credentials)
{
$user = new ApiUser();
$user->vid = $credentials['vid'];
$user->name = $credentials['name'];
$user->surname = $credentials['surname'];
return $user;
}
public function validateCredentials(UserContract $user, array $credentials)
{
return TRUE; //already validated at the API
}
}
Homepage Controller (Here both check methods return FALSE)
class PagesController extends Controller
{
public function index($folder= '', $page= 'inicio')
{
if( !(Auth::check() || Auth::guard('ivao')->check()) ) return redirect('/login');
...irrelevant code...
Please let me know if you need further information. Hope someone can help. I'm stuck. Thanks.

how to put only session auth in laravel

Web.php
Route::group(['middleware'=>'auth:admin'], function(){
Route::resource('dashboard', 'DashboardController');
Route::group(['prefix'=>'users','namespace'=>'User','as'=>'u.'], function(){
Route::resource('list', 'ListController');
Route::resource('segments', 'SegmentController');
});
Route::group(['prefix'=>'sales','namespace'=>'Sales','as'=>'s.'], function(){
Route::resource('credits', 'CreditController');
Route::resource('packages', 'PackageController');
});
});
RedirectIfAuthenticated
class RedirectIfAuthenticated
{
public function handle($request, Closure $next, $guard)
{
if(Session::has('admin_session')){
return redirect('admin/dashboard');
}
// if (Auth::guard($guard)->check()) {
// return redirect(RouteServiceProvider::HOME);
// }
return $next($request);
}
}
AuthController
public function login(Request $request)
{
$serviceAccount = ServiceAccount::fromJsonFile(__DIR__.'/firebaseKey.json');
$firebase= (new Factory)->withServiceAccount($serviceAccount)->create();
$this->database = $firebase->getDatabase();
$auth = $firebase->getAuth();
// if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password])) {
// return redirect('admin/dashboard');
// }
try {
if($user = $auth->verifyPassword($request->email,$request->password)){
Session::put('admin_session',$user);
return redirect('admin/dashboard');
}
} catch (\Kreait\Firebase\Exception\Auth\InvalidPassword $e) {
echo 'wrong password'; die();
} catch (\Kreait\Firebase\Auth\SignIn\FailedToSignIn $e) {
echo 'invalid email'; die();
}
}
How to put only session authentication on above-mentioned routes?
As I want to put firebase authentication so laravel's wouldn't work here,
So I just want to implement simple isset(session('admin_session')) functionality which will be common for all routes...
Anyone, please suggest me how to implement it... it keeps redirecting!
Change the middleware group to a new middleware name:
Web.php
Route::group(['middleware'=>'role'], function(){ //or the name you want to use
Route::resource('dashboard', 'DashboardController');
Route::group(['prefix'=>'users','namespace'=>'User','as'=>'u.'], function(){
Route::resource('list', 'ListController');
Route::resource('segments', 'SegmentController');
});
Route::group(['prefix'=>'sales','namespace'=>'Sales','as'=>'s.'], function(){
Route::resource('credits', 'CreditController');
Route::resource('packages', 'PackageController');
});
});
Create a new middleware by php artisan make:middleware Role :
Role.php (Middleware)
<?php
namespace App\Http\Middleware;
use Session;
use Closure;
class Role
{
public function handle($request, Closure $next)
{
if(Session::has('admin_session')) {
return $next($request);
}
return redirect()->route('login');
}
}
Modify the RedirectIfAuthenticated middleware to this:
RedirectIfAuthenticated.php
class RedirectIfAuthenticated
{
public function handle($request, Closure $next, $guard = null)
{
if (Session::has('admin_session')) {
return redirect('admin/dashboard');
}
return $next($request);
}
}
Modify AuthController to this:
AuthController.php
public function login(Request $request)
{
if ($auth = $this->firebase->getAuth()) {
try {
$user = $auth->verifyPassword($request->email, $request->password);
Session::put('admin_session',$user);
return redirect('admin/dashboard');
}
catch (\Kreait\Firebase\Exception\Auth\InvalidPassword $e) {
return back(); // code for wrong password
}
catch (\Kreait\Firebase\Auth\SignIn\FailedToSignIn $e) {
return back(); //code for user doesn't exists
}
}
return back(); // something went wrong
}

auth()->user() return null in ServiceProvider

i try to get the user id in ServiceProvider but auth()->user() return null after successfully login where is the problem ?
It doesn't just work in test mode
public function boot()
{
dd(auth()->user()); // => return null
try {
Permission::get()->map(function ($permission) {
// dd('$permission');
Gate::define($permission->slug, function ($user) use ($permission) {
return $user->hasPermissionTo($permission);
});
});
} catch (\Exception $e) {
report($e);
}
Try using:
use Auth;
public function boot(){
Auth::user(); //or
Auth::user()->name; //or
Auth::user()->get();
}

Laravel: How the best way for redirect a default laravel user to admin page if user is admin or to user page if user is not admin?

The User model has an isAdmin() function to check if the user is an administrator. What to do next?
The best way is to use default laravel LoginController located under App\Http\Controllers\Auth\LoginController.
In that controller you can override authenticated method that is injected from AuthenticatesUsers trait, by simply adding that method in LoginController:
* #param Request $request
* #param $user
*/
protected function authenticated(Request $request, $user)
{
if ($user->isAdmin()) {
return redirect(route('admin-dashboard'));
//redirect to desired place since user is admin.
}
}
Best practique is whit roles, and you add role on your Routes::middleware,
Route::group(['middleware' => ['auth', 'roles:admin']], function () {
//Your routes
});
Kernel.php
'roles' => Middleware\CheckRole::class,
Create middleware
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
public function handle($request, Closure $next, ...$role)
{
if ($request->user()->hasAnyRole($role)) {
return $next($request);
}
return redirect(route('hour'));
}
}
create function on User model
public function authorizeRole($role)
{
if ($this->hasAnyRole($role)) {
return true;
}
return abort(401, 'Unauthorized.');
}
public function hasAnyRole($roles)
{
if (is_array($roles)) {
foreach ($roles as $role) {
if ($this->hasRole($role)) {
return true;
}
}
} else {
if ($this->hasRole($roles)) {
return true;
}
}
return false;
}
public function hasRole($role)
{
if ($this->role()->where('name', $role)->first()) {
return true;
}
return false;
}
public function role()
{
return $this->belongsTo('App\Role')->withDefault();
}
And Role model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
public function user()
{
return $this->hasMany('App\User');
}
}
Is more code, but best way for this action

Notification fake assertion not working on password reset test?

I was trying to make tests for my auth routes. For password reset route I am trying to make in which I am faking the notification module of laravel and asserting as per the docs.
This is my test file
public function testUserReceivesAnEmailWithAPasswordResetLink()
{
$this->withoutExceptionHandling();
Notification::fake();
$user = factory(User::class)->make();
$response = $this->post($this->passwordEmailPostRoute(), [
'email' => $user->email,
]);
$this->assertNotNull($token = DB::table('password_resets')->where('email', $user->email));
Notification::assertSentTo($user, PasswordReset::class);
}
While I am running this, I am getting notification was not sent error.
My User model is like this:
use Notifiable, HasApiTokens, SoftDeletes, Uuidable, Switchable, ResourceMapper;
public function role()
{
return $this->belongsTo('App\Models\Role');
}
public function company()
{
return $this->belongsTo('App\Models\Company');
}
public function AauthAccessToken()
{
return $this->hasMany('App\Models\OauthAccessToken');
}
public function isRole($role)
{
return $this->role->uuid == $role;
}
public function sendPasswordResetNotification($token)
{
$this->notify(new PasswordReset($token));
}
public function resource()
{
return $this->morphTo();
}
I can't figure whats the exact problem.

Resources