11 августа 2025 г.
Установка 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 можно использовать:
Регистрация:
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 показывает статьи только после получения токена!