Multi JWT Auth с Laravel и Mongodb - PullRequest
0 голосов
/ 06 июня 2018

У меня есть три типа Authenticatable модели, и мне нужно иметь отдельную аутентификацию JWT для каждой.Позвольте мне подробнее рассказать о моей проблеме.

Я использую MongoDB в качестве базы данных, а Laravel MongoDB - это пакет, который я использую.

User, Admin и ServiceProvider - мои модели.

Чтобы иметь JWT-аутентификацию в Laravel, я использую пакет 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, он возвращает ноль!

Любое решение будет оценено.

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

Вот что вам нужно, чтобы добавить возможность мульти-аутентификации с JWT в мой проект.

  1. В пакете tymon JWT auth JWTAuthServiceProvider измените тип определения Tymon\JWTAuth\JWTAuth и Tymon\JWTAuth\Providers\User\UserInterface с singleton на 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' промежуточного программного обеспечения к маршрутам, которыеВы хотите.

Но даже с этими шагами, Вы, должно быть, столкнулись с новой проблемой.Речь шла о получении аутентификационного токена по учетным данным при входе в систему и получении аутентификационного пользователя из токена.(Похоже, что изменение значения конфигурации не влияет на JWTAuth::attempt($credentials) и $this->auth->authenticate($token))

Для решения проблемы получения доступа с помощью токена:

Создайте новыйmiddleware CustomGetUserFrom Token which extends of Tymon's jwt.auth middleware, I mean GetUserFromToken and in line 35, and **replace** $ user = $ this-> auth-> authenticate ($ token); with $ user = JWTAuth :: toUser ($ token); `

И для решения проблемы получения токена аутентификации по учетным данным при входе в систему:

Сначала найдите пользователя авторизации, а затем проверьтесуществование пользователя и действительный пароль с помощью метода 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);
}

Я не уверен в этом, но думаю, что это правда, пока не найду правильный способ сделать это!

Вывод:

Наличие возможности многократной аутентификации JWT в Laravel, возможно, имеет много других способов сделать, но мне это понравилось, и я поделился этим, чтобы быть полезным.

Я думаю, что единственным важным пунктом этой проблемы был app()->make('tymon.jwt.provider.user');, возможность переделать пользовательский провайдер после изменения значений конфигурации.

Любые другие решения будут оценены.

0 голосов
/ 10 июня 2018

Вы должны использовать только одну модель (фактически таблицу) для аутентификации.Когда вы сохраняете пользователя и администратора, вы можете справиться с этим.Но когда у пользователя есть запрос с токеном jwt, вы не можете знать, какая модель вернется (Admin или User)?

Использовать только модель пользователя для аутентификации, а модель Admin расширяется от User.

Перепроектировать базу данных следующим образом:

пользователей таблица: идентификатор, электронная почта, пароль, is_admin

user_details таблица: идентификатор,user_id, имя, фамилия, фамилия, city_abbr, телефон

admin_details таблица: id, идентификатор_пользователя, имя, телефон

Поставьте эту Admin модель для переопределениявсе запросы:

protected $table = "users";

public function newQuery()
{
    return parent::newQuery()
        ->where("is_admin", true);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...