Lravel 5.4: JWT API with multi-auth on two tables, one works and the other doesn't

I use...

  • Laravel 5.4
  • tymon / jwt-auth: 1.0.0-rc.2

I have an application with two authentications. One API is customers , and the other is drivers , each has its own table.

Now let me briefly describe the installation of the JWT package and the updates I made on it.

  • I installed the package exactly as described in the JWT .
  • Now it's a quick start. Here I updated two Models , one of them is User and the second Driver .
  • Comes to Configure Auth guard again, I used the configuration for two guards to show a snapshot of my auth.php .

     'defaults' => [ 'guard' => 'api', 'passwords' => 'users', ], 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'jwt', 'provider' => 'users', ], 'driver' => [ 'driver' => 'session', 'provider' => 'drivers', ], 'driver-api' => [ 'driver' => 'jwt', 'provider' => 'drivers', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], 'drivers' => [ 'driver' => 'eloquent', 'model' => App\Models\Driver::class, ], ], 
  • Now continue the application with authentication routes , here is my Routes for two Models

Here are User and Driver Routes

 Route::group( [ 'prefix' => 'auth', 'middleware' => 'api' ], function () { ....... }); Route::group( [ 'prefix' => 'driver', 'middleware' => 'api' ], function () { ....... }); 
  • Now comes the AuthController

in the JWT documentation, which is written as construct .

 public function __construct() { $this->middleware('auth:api', ['except' => ['login']]); } 

I found an article that suggested doing something like this to switch between the two models that we have.

so here it looks with my controller now.

 public function __construct() { $this->user = new User; $this->driver = new Driver; } public function userLogin( Request $request ) { Config::set( 'jwt.user', 'App\Models\User' ); Config::set( 'auth.providers.users.model', User::class ); $credentials = $request->only( 'email', 'password' ); $token = null; try { if ( $token = $this->guard()->attempt( $credentials ) ) { return response()->json( [ 'response' => 'error', 'message' => 'invalid_email_or_password', ] ); } } catch ( JWTAuthException $e ) { return response()->json( [ 'response' => 'error', 'message' => 'failed_to_create_token', ] ); } return response()->json( [ 'response' => 'success', 'result' => [ 'token' => $token, 'message' => 'I am front user', ], ] ); } public function driverLogin( Request $request ) { Config::set( 'jwt.user', 'App\Models\Driver' ); Config::set( 'auth.providers.users.model', Driver::class ); $credentials = $request->only( 'email', 'password' ); $token = null; try { if ( ! $token = $this->guard()->attempt( $credentials ) ) { return response()->json( [ 'response' => 'error', 'message' => 'invalid_email_or_password', ] ); } } catch ( JWTAuthException $e ) { return response()->json( [ 'response' => 'error', 'message' => 'failed_to_create_token', ] ); } return response()->json( [ 'response' => 'success', 'result' => [ 'token' => $token, 'message' => 'I am driver user', ], ] ); } public function me() { return response()->json( $this->guard()->user() ); } public function logout() { $this->guard()->logout(); return response()->json( [ 'message' => 'Successfully logged out' ] ); } public function refresh() { return $this->respondWithToken( $this->guard()->refresh() ); } protected function respondWithToken( $token ) { return response()->json( [ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => $this->guard()->factory()->getTTL() * 60 ] ); } public function guard() { return Auth::guard(); } 

Now that happens, and the problems that I encountered

Now the api driver works like login only Ex.

localhost:8000/api/driver/login Works fine

but when trying to get a custom id driver like this

localhost:8000/api/driver/me returns an empty array

The second issue.

use login from interface for Ex. http://localhost:8000/login it goes back to the login screen without any errors, because the login information is correct, but defaults in auth.php is 'guard'=>'api' if I change it on 'guard'=>'web' , it logs in correctly.

even User API for Ex. localhost:8000/api/auth/login always return

 { "response": "error", "message": "invalid_email_or_password" } 

Update

I decided half way. I updated AuthController to be something like this.

 public function __construct() { if ( Request()->url() == '/api/driver/me' ) { $this->middleware( 'auth:driver-api', [ 'except' => [ 'login' ] ] ); } elseif ( Request()->url() == '/api/customer/me' ) { $this->middleware( 'auth:api', [ 'except' => [ 'login' ] ] ); } } 

and the login function will look something like this.

 public function login() { if ( Request()->url() == '/api/driver' ) { Config::set( 'auth.providers.users.model', Driver::class ); $credentials = request( [ 'email', 'password' ] ); if ( ! $token = auth()->attempt( $credentials ) ) { return response()->json( [ 'error' => 'Unauthorized' ], 401 ); } return $this->respondWithToken( $token ); } Config::set( 'auth.providers.users.model', User::class ); $credentials = request( [ 'email', 'password' ] ); if ( ! $token = auth()->attempt( $credentials ) ) { return response()->json( [ 'error' => 'Unauthorized' ], 401 ); } return $this->respondWithToken( $token ); } 

but still the problem in auth.php here

 'defaults' => [ 'guard' => 'driver-api', 'passwords' => 'users', ], 

here I need to switch 'guard'=>'api' to 'guard'=>'driver-api' in case the localhost:8000/api/driver/login url is localhost:8000/api/driver/login and 'guard'=>'api' in case if the url request is localhost:8000/api/customer/login any way for this.

Update 2

Here is the Driver Model

 use Tymon\JWTAuth\Contracts\JWTSubject; use Illuminate\Foundation\Auth\User as Authenticatable; class Driver extends Authenticatable implements JWTSubject { protected $guard = 'driver'; protected $fillable = [ ... 'email', 'password', ... ]; protected $hidden = [ 'password', 'remember_token', ]; public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return []; } } 

and User Model

 use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { use Notifiable; protected $fillable = [ 'name', 'email', 'password', ]; protected $hidden = [ 'password', 'remember_token', ]; public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return []; } 

I need help, ideas please.

+2
source share
3 answers

First, let me thank you @AmrAbdelRahman for your efforts and your time.

My problem was that the application always used my default authentication "guard" as my default value looks like

 'defaults' => [ 'guard' => 'api', 'passwords' => 'users', ], 

so every time I try to authenticate another user that was unsuccessful during default authentication, it is api , in which case it should use driver .

what I did in my case was to create a switch in App\Providers\AppServiceProvider under boot , this is how it looks like

 $this->app['router']->matched(function (\Illuminate\Routing\Events\RouteMatched $e) { $route = $e->route; if (!array_has($route->getAction(), 'guard')) { return; } $routeGuard = array_get($route->getAction(), 'guard'); $this->app['auth']->resolveUsersUsing(function ($guard = null) use ($routeGuard) { return $this->app['auth']->guard($routeGuard)->user(); }); $this->app['auth']->setDefaultDriver($routeGuard); }); 

Now in my case, if $guard =api reads that guard and acts correctly, and if it is driver , it will use the new guard and act as expected. Hope this helps someone in the future.

0
source

My example when I used multi auth with jwt

I have 2 models: 1. users 2. admins

routes:

 Route::post('auth/userlogin', ' ApiController@userLogin '); Route::post('auth/adminlogin', ' ApiController@adminLogin '); 

controller:

 namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Controllers\Controller; use App\Http\Requests; use Config; use JWTAuth; use JWTAuthException; use App\User; use App\Admin; class ApiController extends Controller { public function __construct() { $this->user = new User; $this->admin = new Admin; } public function userLogin(Request $request){ Config::set('jwt.user', 'App\User'); Config::set('auth.providers.users.model', \App\User::class); $credentials = $request->only('email', 'password'); $token = null; try { if (!$token = JWTAuth::attempt($credentials)) { return response()->json([ 'response' => 'error', 'message' => 'invalid_email_or_password', ]); } } catch (JWTAuthException $e) { return response()->json([ 'response' => 'error', 'message' => 'failed_to_create_token', ]); } return response()->json([ 'response' => 'success', 'result' => [ 'token' => $token, 'message' => 'I am front user', ], ]); } public function adminLogin(Request $request){ Config::set('jwt.user', 'App\Admin'); Config::set('auth.providers.users.model', \App\Admin::class); $credentials = $request->only('email', 'password'); $token = null; try { if (!$token = JWTAuth::attempt($credentials)) { return response()->json([ 'response' => 'error', 'message' => 'invalid_email_or_password', ]); } } catch (JWTAuthException $e) { return response()->json([ 'response' => 'error', 'message' => 'failed_to_create_token', ]); } return response()->json([ 'response' => 'success', 'result' => [ 'token' => $token, 'message' => 'I am Admin user', ], ]); } } 

I hope this helps.

+1
source

There is no need to change providers in config/auth.php .

You can change the __construct function in each of your controllers as follows. So jwt knows which model to authenticate.

Drivercontroller

 function __construct() { Config::set('jwt.user', Driver::class); Config::set('auth.providers', ['users' => [ 'driver' => 'eloquent', 'model' => Driver::class, ]]); } 
0
source

All Articles