Тест на вакансию

Добавление авторизации к REST API на PHP фреймворке Laravel

11 августа 2025 г.
91

Установка Laravel

Создание проекта и все остальные действия описаны в Создание REST API на PHP фреймворке Laravel.

Создание контроллера авторизации API

Создадим контроллер, который будет обрабатывать запросы на регистрацию и аутентификацию. Сделаем это с помощью Artisan:
php artisan make:controller AuthController
Отредактируем файл контроллера (app/Http/Controllers/AuthController.php):
<?php

namespace App\Http\Controllers;

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

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8|confirmed',
        ]);
        if ($validator->fails()) {
            return response()->json(['errors' => $validator->errors()], 422);
        }
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);
        $token = $user->createToken('auth_token')->plainTextToken;
        return response()->json([
            'access_token' => $token,
            'token_type' => 'Bearer',
        ]);
    }
    public function login(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|string|email',
            'password' => 'required|string',
        ]);
        if ($validator->fails()) {
            return response()->json(['errors' => $validator->errors()], 422);
        }
        $user = User::where('email', $request->email)->first();
        if (!$user || !Hash::check($request->password, $user->password)) {
            return response()->json(['message' => 'Incorrect credentials'], 401);
        }
        $token = $user->createToken('auth_token')->plainTextToken;
        return response()->json([
            'access_token' => $token,
            'token_type' => 'Bearer',
        ]);
    }
    public function logout(Request $request)
    {
        $request->user()->currentAccessToken()->delete();
        return response()->json(['message' => 'Successfully logged out']);
    }
    public function user(Request $request)
    {
        return response()->json($request->user());
    }
}
Ключевые моменты в контроллере::
  • register(Request $request):
    • Валидирует данные, полученные из запроса (имя, email, пароль, подтверждение пароля).
    • Если валидация не удалась, возвращает ошибки валидации с кодом состояния 422 (Unprocessable Entity).
    • Создает нового пользователя в базе данных (хеширует пароль).
    • Создает новый токен доступа для пользователя с помощью $user->createToken('auth_token')->plainTextToken;.
    • Возвращает токен доступа и тип токена (Bearer) в формате JSON с кодом состояния 201 (Created).
  • login(Request $request):
    • Валидирует данные, полученные из запроса (email, пароль).
    • Если валидация не удалась, возвращает ошибки валидации с кодом состояния 422 (Unprocessable Entity).
    • Находит пользователя в базе данных по email.
    • Проверяет, что пароль пользователя верен, используя Hash::check().
    • Если учетные данные неверны, возвращает сообщение об ошибке с кодом состояния 401 (Unauthorized).
    • Создает новый токен доступа для пользователя с помощью $user->createToken('auth_token')->plainTextToken;.
    • Возвращает токен доступа и тип токена (Bearer) в формате JSON с кодом состояния 200 (OK).
  • logout(Request $request):
    • Удаляет текущий токен доступа пользователя с помощью $request->user()->currentAccessToken()->delete();.
    • Возвращает сообщение об успешном выходе из системы.
  • user(Request $request):
    • Возвращает информацию о текущем аутентифицированном пользователе. Этот метод используется для получения данных о пользователе после успешной аутентификации.

Изменение модели User

Отредактируем файл модели (app/Models/User.php):
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
    protected $fillable = [
        'name',
        'email',
        'password',
    ];
    protected $hidden = [
        'password',
        'remember_token',
    ];
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }
}
 

Определение маршрутов API

Переопределим маршруты API в файле routes/api.php:
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ArticleController;
use App\Http\Controllers\AuthController;

Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::get('/login', function () {
    return response()->json([
        'message' => 'Authentication required',
        'login_endpoint' => '/api/login',
        'method' => 'POST'
    ], 401);
})->name('login');
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', [AuthController::class, 'user']);
    Route::post('/logout', [AuthController::class, 'logout']);
    Route::apiResource('articles', ArticleController::class);
});
Обратите внимание, что проблема кроется в автоматическом поведении Laravel Sanctum - при неудачной аутентификации система пытается перенаправить запрос на GET-маршрут /api/login, хотя у нас существует только POST-версия этого эндпоинта.

Вот почему мы специально реализуем обработку GET-запроса:
  • Причина проблемы: Sanctum по умолчанию использует RedirectIfAuthenticated middleware, который ищет GET-маршрут 'login'
  • Наше решение:
    • Явно создаем GET-эндпоинт /api/login
    • Возвращаем информативный JSON-ответ вместо редиректа
    • Сохраняем согласованность API (все ответы в JSON-формате)
Это решение:
  • Пресекает попытки автоматического редиректа
  • Сохраняет REST-стиль API
  • Дает клиенту четкие инструкции
  • Избегает ошибки "Route not defined"
Альтернативный подход - полное отключение редиректов через конфигурацию Sanctum, но явная обработка GET-запроса считается более правильной практикой для API.

Тестирование API

Запускаем наш API:
php artisan serve
Сервер запуститься по адресу http://127.0.0.1:8000.

Для тестирования API можно использовать:
  • Postman
  • curl
Регистрация:
curl -X POST \
  http://localhost:8000/api/register \
  -H 'Content-Type: application/json' \
  -d '{
      "name": "Ivan Ivanov",
      "email": "ivan@ivanov.ru",
      "password": "password",
      "password_confirmation": "password"
  }'
Вход:
curl -X POST \
  http://localhost:8000/api/login \
  -H 'Content-Type: application/json' \
  -d '{
      "email": "ivan@ivanov.ru",
      "password": "password"
  }'
Получение данных о пользователе (после регистрации или входа):
curl -H "Authorization: Bearer {ваш_токен}" http://localhost:8000/api/user
Выход:
curl -X POST \
  -H "Authorization: Bearer {ваш_токен}" http://localhost:8000/api/logout
Получение всех статей:
curl -X GET \
  -H "Authorization: Bearer {ваш_токен}" http://localhost:8000/api/articles
Теперь наш API для работы со статьями на фреймворке Laravel показывает статьи только после получения токена!
Поделиться: