我有三种类型的Authenticatable模型,我需要为每种模型分别进行JWT身份验证。让我解释一下我的问题。
我正在使用 MongoDB 作为我的数据库,Laravel MongoDB是我使用的包。
User
,Admin
和ServiceProvider
是我的模特。
要在Laravel中使用JWT auth,我使用jwt-auth包。用户模型(集合)没问题。当我想将JWT与任何其他模型一起使用时它不起作用并再次使用user
执行所有操作。
我搜索了很多,我发现要更改提供者用户模型,我可以使用Config::set();
方法,如下所示,
Config::set('jwt.user', Admin::class);
Config::set('auth.providers.users.model', Admin::class);
但对JWT认证没有影响。 (我使用'jwt.user'
方法检查了'auth.providers.users.model'
和Config::get()
的值并将其返回,它已更改为'App\Admin'
)。
需要说明的是,根据软件包的文档,我的代码尽可能简单。
这是我的UserController
代码:
class UserController extends Controller
{
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255',
'password' => 'required|min:6'
]);
if ($validator->fails()) {
return response()->json($validator->errors());
}
$credentials = $request->only('email', 'password');
try {
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
return response()->json(['error' => 'could_not_create_token'], 500);
}
$user = User::where('email', $request->email)->first();
return response()->json([
'user' => $user,
'token' => $token
]);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255|unique:users',
'phone' => 'required|valid_phone|unique:users',
'password' => 'required|min:6',
'first_name' => 'required',
'last_name' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->errors());
}
User::create([
'phone' => $request->get('phone'),
'first_name' => $request->get('first_name'),
'last_name' => $request->get('last_name'),
'city_abbr' => $request->get('city_abbr'),
'email' => $request->get('email'),
'password' => bcrypt($request->get('password')),
]);
$user = User::first();
$token = JWTAuth::fromUser($user);
return response()->json([
'user' => $user,
'token' => $token
]);
}
}
我的AdminController
:
class AdminController extends Controller
{
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255',
'password' => 'required|min:6'
]);
if ($validator->fails()) {
return response()->json($validator->errors());
}
$credentials = $request->only('email', 'password');
Config::set('jwt.user', Admin::class);
Config::set('auth.providers.users.model', Admin::class);
try {
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
return response()->json(['error' => 'could_not_create_token'], 500);
}
$admin = Admin::where('email', $request->email)->first();
return response()->json([
'admin' => $admin,
'token' => $token
]);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255|unique:admins',
'phone' => 'required|valid_phone|unique:admins',
'password' => 'required|min:6',
'name' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->errors());
}
$admin = Admin::create([
'phone' => $request->get('phone'),
'name' => $request->get('name'),
'access' => $request->get('access'),
'email' => $request->get('email'),
'password' => bcrypt($request->get('password')),
]);
Config::set('jwt.user', Admin::class);
Config::set('auth.providers.users.model', Admin::class);
$token = JWTAuth::fromUser($admin);
return response()->json([
'admin' => $admin,
'token' => $token
]);
}
}
我在某个地方错了吗? 对此有什么解决方案吗?
更新
为了确保MongoDB功能,我使用关系数据库测试以上所有操作,实际上是MySQL。什么都没改变!
JWTAuth会生成令牌但是当我使用除toUser
之外的任何模型运行User
方法时,它会返回null!
任何解决方案都将受到赞赏。
答案 0 :(得分:2)
这是将JWT的多重身份验证功能添加到我的项目中必须要做的事情。
在tymon JWT auth包中。在JWTAuthServiceProvider
中,用Tymon\JWTAuth\JWTAuth
方法将Tymon\JWTAuth\Providers\User\UserInterface
和singleton
的定义类型从bind
更改为bootBindings
。
定义了一个新的中间件,下面的代码是其handle
方法:
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); }
在modifyJWTAuthUser
中定义了一个名称为Helpers
的函数,这是它的内部:
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;
} }
在$routeMiddleware
中引入了另一个Kernel.php
,如下所示:
...
'modify.jwt.auth.user' => ChangeJWTAuthUser::class,
,最后一步,将'modify.jwt.auth.user'
中间件添加到所需的路由。
但是即使执行了这些步骤,您仍然必须遇到一个新问题。这是关于通过登录凭证获取 auth令牌,并从令牌中获取 auth用户。 (似乎更改配置值对JWTAuth::attempt($credentials)
和$this->auth->authenticate($token)
无效)
要解决从令牌问题获取身份验证用户的问题:
创建一个新的中间件CustomGetUserFrom
令牌which extends of Tymon's
jwt.auth middleware, I mean
GetUserFromToken and in line 35, and **replace**
$ user = $ this-> auth-> authenticate($ token); {{ 1}} $ user = JWTAuth :: toUser($ token);`
并解决登录问题中通过凭据获取 auth令牌的问题:
首先,找到身份验证用户,然后,检查用户是否存在,并使用with
方法验证密码,如果这些条件返回true,则从用户生成令牌。这是登录代码:
Hash::check()
我不确定这种方式,但是我认为这是真的,除非找到正确的方法!
结论:
在Laravel中具有多JWT身份验证功能可能还有许多其他方法,但我确实喜欢并分享了这一点。
我认为此问题的唯一重要点是$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);
}
,它是在配置值更改后重新制作用户提供程序的功能。
任何其他解决方案将不胜感激。
答案 1 :(得分:0)
您应该只使用一个模型(实际上是表)进行身份验证。当您保存用户和管理员时,您可以处理它。但是当用户请求使用jwt令牌时,您无法知道将返回哪个模型(管理员或用户)?
仅使用用户模型进行身份验证,管理模型从用户扩展。
重新设计数据库,如下所示:
用户表:id,电子邮件,密码,is_admin
user_details 表:id,user_id,first_name,last_name,city_abbr,phone
admin_details 表:id,user_id,name,phone
将此管理模型用于覆盖所有查询:
protected $table = "users";
public function newQuery()
{
return parent::newQuery()
->where("is_admin", true);
}