【问题标题】:Multi Jwt Auth with Laravel and Mongodb使用 Laravel 和 Mongodb 进行多 Jwt 身份验证
【发布时间】:2018-11-16 14:12:30
【问题描述】:

我有三种类型的 Authenticatable 模型,我需要为每种模型进行单独的 JWT 身份验证。让我详细解释一下我的问题。

我使用 MongoDB 作为我的数据库,Laravel MongoDB 是我使用的包。

UserAdminServiceProvider 是我的模型。

为了在 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

标签: php mongodb laravel laravel-5 jwt


【解决方案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 的多身份验证功能。

  1. tymon JWT auth 包中。在JWTAuthServiceProvider 中,在bootBindings 方法中将Tymon\JWTAuth\JWTAuthTymon\JWTAuth\Providers\User\UserInterface 定义类型从singleton 更改为bind

  2. 定义了一个新的中间件,下面的代码是它的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);    }
    
  3. 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;
    }    }
    
  4. Kernel.php 中引入了另一个$routeMiddleware,如下所示:

    ... 'modify.jwt.auth.user' => ChangeJWTAuthUser::class,

  5. 最后一步,将'modify.jwt.auth.user' 中间件添加到您想要的路由中。

但即使有了这些步骤,您一定遇到了新问题。它是关于通过登录凭据获取 auth 令牌 并从令牌中获取 auth 用户。 (似乎更改配置值不会影响JWTAuth::attempt($credentials)$this->auth->authenticate($token)

解决从令牌获取授权用户的问题:

创建一个新的中间件CustomGetUserFromTokenwhich extends of Tymon'sjwt.authmiddleware, I meanGetUserFromTokenand 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');,能够在配置值更改后重新制作用户提供程序。

任何其他解决方案将不胜感激。

【讨论】:

    猜你喜欢
    • 2016-05-18
    • 2016-03-21
    • 2016-04-20
    • 2019-08-18
    • 2016-04-07
    • 2020-07-23
    • 2021-02-08
    • 2017-04-27
    • 2017-11-25
    相关资源
    最近更新 更多