使用Laravel和Mongodb进行Multi Jwt Auth

时间:2018-06-06 19:22:05

标签: php mongodb laravel laravel-5 jwt

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

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

UserAdminServiceProvider是我的模特。

要在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!

任何解决方案都将受到赞赏。

2 个答案:

答案 0 :(得分:2)

这是将JWT的多重身份验证功能添加到我的项目中必须要做的事情。

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

  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. 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;
    }    }
    
  4. $routeMiddleware中引入了另一个Kernel.php,如下所示:

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

  5. ,最后一步,将'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);
}