Multi Jwt Auth with Laravel and Mongodb
Here is what you must fo to add multi auth ability with JWT to my project.
In tymon JWT auth package. In
JWTAuthServiceProvider
, ChangeTymon\JWTAuth\JWTAuth
andTymon\JWTAuth\Providers\User\UserInterface
definition type fromsingleton
tobind
inbootBindings
method.Defined a new middleware and below code is its
handle
method:public function handle($request, Closure $next){ if (!$request->header('Auth-Type')) { return response()->json([ 'success' => 0, 'result' => 'auth type could not found!' ]); } switch ($request->header('Auth-Type')) { case 'user': $auth_class = 'App\User'; break; case 'admin': $auth_class = 'App\Admin'; break; case 'provider': $auth_class = 'App\ServiceProvider'; break; default: $auth_class = 'App\User';}if (!Helpers::modifyJWTAuthUser($auth_class)) return response()->json([ 'status' => 0, 'error' => 'provider not found!' ]);return $next($request); }
Defined a function with name
modifyJWTAuthUser
inHelpers
and here is its inner:public static function modifyJWTAuthUser($user_class){if (!$user_class || ( $user_class != 'App\User' && $user_class != 'App\Admin' && $user_class != 'App\ServiceProvider' )) return false;try { Config::set('jwt.user', $user_class); Config::set('auth.providers.users.model', $user_class); app()->make('tymon.jwt.provider.user'); return true;} catch (\Exception $e) { return false;} }
Introduced another
$routeMiddleware
like below inKernel.php
:...'modify.jwt.auth.user' => ChangeJWTAuthUser::class,
and the last step, Adding
'modify.jwt.auth.user'
middleware to the routes that you want.
But even with this steps, You must have encountered a new issue. It was about getting the auth token by credentials in login and getting auth user from the token. (It seems that changing config value not effect on JWTAuth::attempt($credentials)
and $this->auth->authenticate($token)
)
To solve the getting auth user from the token issue:
Create a new middleware CustomGetUserFrom
Tokenwhich extends of Tymon's
jwt.authmiddleware, I mean
GetUserFromTokenand in line 35, and **replace**
$user = $this->auth->authenticate($token);with
$user = JWTAuth::toUser($token);`
And to solve getting the auth token by credentials in login issue:
At first, Find the auth user and after that, check the user existence and valid the password with Hash::check()
method, if these conditions return true, Generate a token from the user. Here is login code:
$admin = Admin::where('email', $request->email)->first();if (!$admin || !Hash::check($request->get('password'), $admin->password)) { return response()->json([ 'success' => '0', 'error' => 'invalid_credentials' ], 401);}
I'm not sure about this way but I think it's true until finding a correct way to do!
Conclusion:
Having multi JWT auth ability in Laravel perhaps have many other ways to do but I did like this and shared it to be helpful.
I think the only important point of this issue was app()->make('tymon.jwt.provider.user');
, the ability to remake user provider after config values change.
Any other solutions will be appreciated.
You should use just one model (actually table) for authentication. When you save user and admin you can handle it. But when a user has request with jwt token, you cann't know which model will return (Admin or User)?
Use only User model for authentication and Admin model extends from User.
Redesign database like this:
users table : id, email, password, is_admin
user_details table : id, user_id, first_name, last_name, city_abbr, phone
admin_details table: id, user_id, name, phone
Put this your Admin Model for overriding all queries:
protected $table = "users";public function newQuery(){ return parent::newQuery() ->where("is_admin", true);}