JWT auth в Laravel 9

Это подробное руководство по Laravel JWT Authentication. В этой статье мы узнаем, как создавать безопасные REST API в Laravel с использованием JSON Web Token (JWT).

Для защиты API аутентификации пользователей в Laravel мы будем использовать стороннюю библиотеку jwt-auth tymondesigns/jwt-auth.

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

Что такое веб-токен JSON?

JSON Web Token (JWT) — это открытый стандарт (RFC 7519), который представляет собой компактный и автономный метод безопасной передачи информации между сторонами в виде объекта JSON. Цифровая подпись делает передачу данных через JWT надежной и проверенной. JWT построены на секретном алгоритме HMAC или паре открытого/закрытого ключей с использованием RSA или ECDSA.

Зачем нужен JWT?

JWT используется для авторизации и обмена информацией между сервером и клиентом. Он аутентифицирует входящий запрос и обеспечивает дополнительный уровень безопасности для REST API, который лучше всего подходит для целей безопасности.

Как работает JWT?

Информация о пользователе, такая как имя пользователя и пароль, отправляется на веб-сервер с помощью HTTP-запросов GET и POST. Веб-сервер идентифицирует информацию о пользователе, генерирует токен JWT и отправляет его обратно клиенту. Клиент сохраняет этот токен в сеансе, а также устанавливает его в заголовок. При следующем вызове HTTP этот токен проверяется сервером, который возвращает ответ клиенту.

Структура веб-токена JSON

Веб-токены JSON состоят из трех частей, разделенных точками (.)в своей плотной форме.

  • Заголовок
  • Полезная нагрузка
  • Подпись

В конце концов, JWT выглядит примерно так.

xxxxxx.yyyyyyy.zzzzzzzzzz

Установка приложения Laravel

Для начала достаточно, теперь мы приступим к созданию безопасного API Laravel. Давайте установим новый проект laravel, чтобы сформулировать проект Laravel REST API с использованием аутентификации JWT.

Запустите следующую команду, чтобы установить новый проект Laravel.

composer create-project laravel/laravel laravel-jwt-auth --prefer-dist

Подключение к базе данных

Мы создали совершенно новое приложение Laravel с нуля, теперь для хранения регистрационных данных пользователя нам нужно создать базу данных в MySQL и добавить в файл имя базы данных, имя пользователя и пароль .env.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

Для обработки пользовательской аутентификации laravel jwt мы используем MAMP , вы можете получить следующую ошибку миграции.

SQLSTATE[HY000] [2002] No such file or directory (SQL: select * from information_schema.tables where table_schema = laravel_db and table_name = migrations and table_type = ‘BASE TABLE’)

Добавьте одну строку кода под конфигурацией базы данных в файл .env .

DB_HOST=localhost;unix_socket=/Applications/MAMP/tmp/mysql/mysql.sock

Добавить пользователя в базу данных MySQL

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

php artisan migrate

Приведенная выше команда создала таблицу usersвнутри базы данных.

Добавить пользователя в базу данных MySQL

Установка и настройка пакета аутентификации JWT

Выполните следующую команду, чтобы установить tymondesigns/jwt-auth . Это сторонний пакет JWT, который позволяет безопасно аутентифицировать пользователя с помощью веб-токена JSON в Laravel и Lumen.

composer require tymon/jwt-auth

Приведенная выше команда установила пакет jwt-auth в папку vendor, теперь нам нужно перейти к файлу config/app.php и включить service provider laravel внутри providers массива.

Также включите в массив фасады JWTAuth и JWTFactoryaliases .

'providers' => [
    ....
    ....
    Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
],
'aliases' => [
    ....
    'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
    'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
    ....
],

На следующем шаге мы должны опубликовать конфигурацию пакета, следуя команде, скопируйте файлы JWT Auth из папки поставщика в файл config/jwt.php .

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

Для обработки шифрования токена сгенерируйте секретный ключ, выполнив следующую команду.

php artisan jwt:secret

Мы успешно сгенерировали секретный ключ JWT, и вы можете проверить этот ключ внутри .env файла.

JWT_SECRET=secret_jwt_string_key

Настроить модель пользователя

Laravel поставляется с предопределенной Userмоделью; мы можем использовать модель пользователя для процесса аутентификации. На этом этапе мы узнаем, как реализовать пакет jwt-auth в пользовательской модели.

Определите контракт Tymon\JWTAuth\Contracts\JWTSubject перед моделью пользователя. Этот метод требует, чтобы вы определили два метода:

  • getJWTIdentifier(): получить идентификатор, который будет храниться в утверждении субъекта JWT.
  • getJWTCustomClaims(): возвращает массив значений ключа, содержащий любые настраиваемые утверждения, которые необходимо добавить в JWT.

Откройте файл app/Models/User.php и замените следующий код существующим кодом.

<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    use HasFactory, Notifiable;
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];
    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
    
    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier() {
        return $this->getKey();
    }
    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims() {
        return [];
    }    
}

Настройка защиты авторизации

Теперь нам необходимо настроить JWT Auth Guard для защиты процесса аутентификации приложения Laravel. Laravel использует драйвер сеанса для защиты. Тем не менее, мы установили защиту по умолчанию на API, и защитам API приказано использовать драйвер jwt.

Поместите следующий код в файл config/auth.php .

<?php
return [
    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
    ],

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

Контроллер аутентификации

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

Давайте определим контроллер аутентификации вручную или с помощью приведенной ниже команды для управления запросами аутентификации через маршруты, которые мы создали на предыдущем шаге.

 php artisan make:controller AuthController

Поместите следующий код в файл app/Http/Controllers/AuthController.php .

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Validator;

class AuthController extends Controller
{
    /**
     * Create a new AuthController instance.
     *
     * @return void
     */
    public function __construct() {
        $this->middleware('auth:api', ['except' => ['login', 'register']]);
    }

    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request){
    	$validator = Validator::make($request->all(), [
            'email' => 'required|email',
            'password' => 'required|string|min:6',
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);
        }
        if (! $token = auth()->attempt($validator->validated())) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }
        return $this->createNewToken($token);
    }

    /**
     * Register a User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function register(Request $request) {
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|between:2,100',
            'email' => 'required|string|email|max:100|unique:users',
            'password' => 'required|string|confirmed|min:6',
        ]);
        if($validator->fails()){
            return response()->json($validator->errors()->toJson(), 400);
        }
        $user = User::create(array_merge(
                    $validator->validated(),
                    ['password' => bcrypt($request->password)]
                ));
        return response()->json([
            'message' => 'User successfully registered',
            'user' => $user
        ], 201);
    }

    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout() {
        auth()->logout();
        return response()->json(['message' => 'User successfully signed out']);
    }

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh() {
        return $this->createNewToken(auth()->refresh());
    }

    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function userProfile() {
        return response()->json(auth()->user());
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function createNewToken($token){
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth()->factory()->getTTL() * 60,
            'user' => auth()->user()
        ]);
    }
}

Middleware auth:api ПО используется внутри класса объектов; функции внутри контроллера аутентификации не могут быть доступны без действительного токена. Кроме того, мы можем передать имя функции внутри Middleware, которое мы хотим исключить из обязательства токена.

Метод входа используется для предоставления доступа пользователю и запускается при /api/auth/login вызове API. Он аутентифицирует электронную почту и пароль, введенные пользователем в поле электронной почты и пароля. В ответ он генерирует токен авторизации, если находит пользователя внутри базы данных. И наоборот, выдает ошибку, если пользователь не найден в базе данных.

Метод register используется для создания пользователя при /api/auth/register вызове маршрута. Сначала в процессе проверки проверяются такие значения пользователя, как имя, адрес электронной почты и пароль, а затем пользователь регистрируется, если учетные данные пользователя действительны. Затем он генерирует веб-токен JSON, чтобы предоставить пользователю действительный доступ.

Метод logout вызывается при /api/auth/logout запросе API и очищает переданный токен доступа JWT.

Метод обновления создает новый веб-токен JSON за более короткий период, и считается лучшей практикой генерировать новый токен для безопасной системы аутентификации пользователей в Laravel. Он делает недействительным текущего пользователя, вошедшего в систему, если токен JWT не новый.

Метод userProfile отображает данные вошедшего пользователя. Это работает, когда мы помещаем токен аутентификации в заголовки для аутентификации запроса аутентификации, сделанного через API /api/auth/user-profile.

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

Добавление маршрутов аутентификации

Нам нужно определить маршруты аутентификации REST API для процесса аутентификации в приложении Laravel JWT Authentication. Маршруты, которые обслуживаются через route/api.php, имеют префикс, api/ а маршруты аутентификации обозначаются auth/.

Таким образом /api/auth/signup, он становится одинаковым для каждого маршрута, который мы создали для аутентификации.

Нам нужно добавить маршруты аутентификации в route/api.php вместо web.php:

<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::group([
    'middleware' => 'api',
    'prefix' => 'auth'
], function ($router) {
    Route::post('/login', [AuthController::class, 'login']);
    Route::post('/register', [AuthController::class, 'register']);
    Route::post('/logout', [AuthController::class, 'logout']);
    Route::post('/refresh', [AuthController::class, 'refresh']);
    Route::get('/user-profile', [AuthController::class, 'userProfile']);    
});

Протестируйте Laravel JWT Authentication API с помощью Postman

Запустите приложение laravel следующей командой:

php artisan serve

Мы создали безопасный REST API с использованием аутентификации JWT. Чтобы сделать процесс тестирования простым и тонким, мы будем полагаться на Postman.

API аутентификации для входа, регистрации, профиля пользователя, обновления токена и выхода из системы.

API регистрации пользователей в Laravel

Откройте Postman, добавьте API регистрации пользователей в адресную строку и выберите метод HTTP-запроса для POST. Выберите данные формы и добавьте имя, адрес электронной почты, пароль и значения подтверждения пароля в поля ввода. Нажмите кнопку «Отправить», чтобы увидеть ответ, пришедший с сервера.

Регистрация пользователя в Laravel с помощью JWT

Тестирование API входа в Laravel

Чтобы протестировать API входа в Laravel с токеном аутентификации JWT, добавьте данные электронной почты и пароль в поля ввода и нажмите кнопку «Отправить». При успешном входе в систему вы можете увидеть возвращенный токен доступа JWT, тип токена, время истечения срока действия токена и сведения о профиле пользователя.

Протестируйте API входа в Laravel с помощью JWT

Профиль пользователя

Убедитесь, что вы должны определить токен доступа в качестве поля заголовка "Authorization: Bearer Token" для API-интерфейсов REST «Профиль пользователя», «Обновление токена» и «Выход».

Получить профиль пользователя с токеном JWT

Обновление токена JWT в Laravel

Чтобы обновить токен, у нас должен быть действительный токен JWT, вы можете видеть, что мы получаем access_token и пользовательские данные в блоке ответа Postman.

Обновление токена JWT в Laravel

Выход

Мы уничтожили токен JWT при выходе из системы, и вы можете использовать Postman для тестирования Logout API следующим образом.

Выйти в Laravel

Заключение

Итак, в этой статье мы узнали, как создать безопасный REST API для аутентификации пользователей с JWT-аутентификацией. К настоящему моменту у вас есть базовые знания о создании API безопасной аутентификации. Вам также может быть интересно узнать, Как создать REST API с помощью Laravel