使用 Laravel 和 Mongodb 进行多 Jwt 身份验证
Posted
技术标签:
【中文标题】使用 Laravel 和 Mongodb 进行多 Jwt 身份验证【英文标题】:Multi Jwt Auth with Laravel and Mongodb 【发布时间】:2018-11-16 14:12:30 【问题描述】:我有三种类型的 Authenticatable 模型,我需要为每种模型进行单独的 JWT 身份验证。让我详细解释一下我的问题。
我使用 MongoDB 作为我的数据库,Laravel MongoDB 是我使用的包。
User
、Admin
和 ServiceProvider
是我的模型。
为了在 Laravel 中进行 JWT 身份验证,我使用 jwt-auth 包。用户模型(集合)没问题。当我想将 JWT 与任何其他模型一起使用时它不起作用并再次使用 user
完成所有操作。
我搜索了很多,发现要更改提供者用户模型,我可以使用Config::set();
方法,如下所示,
Config::set('jwt.user', Admin::class);
Config::set('auth.providers.users.model', Admin::class);
但对 JWT 身份验证没有影响。 (我用Config::get()
方法检查了'jwt.user'
和'auth.providers.users.model'
的值并返回,已改为'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 生成令牌,但是当我使用除 User
之外的任何模型运行 toUser
方法时,它返回 null!
我们将不胜感激任何解决方案。
【问题讨论】:
你试过$admin = Admin::create(...
吗?恐怕Admin::first()
返回正确的用户。
糟糕!这只是一个测试。我首先使用的正确代码是$admin = Admin::creat...
。我会编辑这个。感谢您的通知! @revo
好吧,顺便说一句,因为我不确定jwt
,我鼓励您为Admin
模型使用完全限定名称。请将这两行 Config::set('jwt.user' , "App\Admin"); Config::set('auth.providers.users.model', \App\Admin::class);
替换为旧的并重新检查。
旧的是什么意思? @revo
我的意思是 old 我的意思是 current。
【参考方案1】:
您应该只使用一个模型(实际上是表)进行身份验证。当您保存用户和管理员时,您可以处理它。但是当用户使用 jwt 令牌请求时,您不知道会返回哪个模型(Admin 或 User)?
仅使用 User 模型进行身份验证,Admin 模型从 User 扩展而来。
像这样重新设计数据库:
users 表:id、email、密码、is_admin
user_details 表:id、user_id、first_name、last_name、city_abbr、phone
admin_details 表:id、user_id、姓名、电话
将此作为您的 Admin 模型来覆盖所有查询:
protected $table = "users";
public function newQuery()
return parent::newQuery()
->where("is_admin", true);
【讨论】:
你说我使用角色,但它是正确的方式吗?我已经了解角色,但在处理大数据的大型项目(如我的)中,它会导致一些滞后,而且正如我在问题顶部提到的那样,我有 3 种可验证的模型,每种模型至少有两种访问类型。我想更多地了解这种类型的身份验证处理(角色)的优点和缺点。这是唯一的方法吗?并注意可以在关系数据库中使用多模型处理多身份验证。 而且在你说的这种类型中,令牌对每个模型都有效! 我要说明的是,您需要使用单个模型(表)来验证 jwt 会话。例如,用户想要列出产品并使用 JWT 发出请求。您将为“auth.providers.users.model”管理员或用户或其他设置使用哪个设置?除了 jwt 令牌,您什么都不知道,您应该可以验证它。您可以通过单个模型(表)使 JWT 有效,然后从电子邮件等基本信息中获取模型。 我把正确答案写在下面,你可以阅读一下。但我的问题奖将是你的。最好的,arkadaş ;)【参考方案2】:这是您必须为我的项目添加 JWT 的多身份验证功能。
在tymon JWT auth 包中。在JWTAuthServiceProvider
中,在bootBindings
方法中将Tymon\JWTAuth\JWTAuth
和Tymon\JWTAuth\Providers\User\UserInterface
定义类型从singleton
更改为bind
。
定义了一个新的中间件,下面的代码是它的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);
在Helpers
中定义了一个名为modifyJWTAuthUser
的函数,这是它的内部:
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;
在Kernel.php
中引入了另一个$routeMiddleware
,如下所示:
...
'modify.jwt.auth.user' => ChangeJWTAuthUser::class,
最后一步,将'modify.jwt.auth.user'
中间件添加到您想要的路由中。
但即使有了这些步骤,您一定遇到了新问题。它是关于通过登录凭据获取 auth 令牌 并从令牌中获取 auth 用户。 (似乎更改配置值不会影响JWTAuth::attempt($credentials)
和$this->auth->authenticate($token)
)
解决从令牌获取授权用户的问题:
创建一个新的中间件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);`
并解决在登录问题中通过凭据获取身份验证令牌:
首先,找到auth用户,然后用Hash::check()
方法检查用户是否存在并验证密码,如果这些条件返回true,则从用户那里生成一个令牌。这是登录代码:
$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);
我不确定这种方式,但我认为在找到正确的方法之前它是正确的!
结论:
在 Laravel 中拥有多 JWT 身份验证功能可能还有很多其他方法可以做,但我确实喜欢这个并分享它以提供帮助。
我认为这个问题唯一重要的一点是app()->make('tymon.jwt.provider.user');
,能够在配置值更改后重新制作用户提供程序。
任何其他解决方案将不胜感激。
【讨论】:
以上是关于使用 Laravel 和 Mongodb 进行多 Jwt 身份验证的主要内容,如果未能解决你的问题,请参考以下文章
使用 Laravel 播种 MongoDB 时的 authenticationDatabase 错误