laravel-12/SANCTUM_SETUP_GUIDE.md

821 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Руководство по установке и настройке Laravel Sanctum с API авторизацией
## Описание
Данное руководство описывает процесс установки и настройки **Laravel Sanctum** для API аутентификации с использованием **wadakatu/laravel-spectrum** для автоматической генерации Swagger документации.
---
## Содержание
1. [Установка пакетов](#1-установка-пакетов)
2. [Настройка Sanctum](#2-настройка-sanctum)
3. [Структура API](#3-структура-api)
4. [API Endpoints](#4-api-endpoints)
5. [Использование API](#5-использование-api)
6. [Swagger документация](#6-swagger-документация)
7. [Команды Artisan](#7-команды-artisan)
---
## 1. Установка пакетов
### 1.1 Установка Laravel Sanctum
```bash
composer require laravel/sanctum
```
### 1.2 Установка wadakatu/laravel-spectrum
```bash
composer require wadakatu/laravel-spectrum
```
### 1.3 Публикация конфигураций
```bash
# Публикация Sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
# Публикация Spectrum (если требуется)
php artisan vendor:publish --provider="Wadakatu\LaravelSpectrum\LaravelSpectrumServiceProvider"
```
### 1.4 Запуск миграций
```bash
php artisan migrate
```
> **Примечание:** Если таблица `personal_access_tokens` уже существует, пропустите этот шаг.
---
## 2. Настройка Sanctum
### 2.1 Обновление модели User
Добавьте трейт `HasApiTokens` в модель `User`:
```php
// app/Models/User.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;
// ...
}
```
### 2.2 Настройка middleware
Обновите файл `bootstrap/app.php`:
```php
// bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {
//
})
->withExceptions(function (Exceptions $exceptions): void {
//
})->create();
```
> **Важно:** Не используйте `statefulApi()` для чистого token-based API, это вызовет ошибку 419 CSRF.
### 2.3 Конфигурация Sanctum
```php
// config/sanctum.php
return [
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),
'guard' => ['web'],
'expiration' => null,
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
'middleware' => [
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],
];
```
---
## 3. Структура API
### 3.1 Директории
```
app/
├── Http/
│ ├── Controllers/
│ │ └── Api/
│ │ ├── AuthController.php
│ │ └── PostController.php
│ ├── Requests/
│ │ ├── LoginRequest.php
│ │ ├── RegisterRequest.php
│ │ ├── StorePostRequest.php
│ │ └── UpdatePostRequest.php
│ └── Resources/
│ ├── PostCollection.php
│ ├── PostResource.php
│ └── UserResource.php
└── Policies/
└── PostPolicy.php
```
### 3.2 API Resources
**Laravel Spectrum** автоматически определяет структуру ответа из API Resources.
```php
// app/Http/Resources/UserResource.php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'role' => $this->role,
'created_at' => $this->created_at,
];
}
}
```
```php
// app/Http/Resources/PostResource.php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'content' => $this->content,
'user_id' => $this->user_id,
'user' => new UserResource($this->whenLoaded('user')),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
```
### 3.3 API Controllers
**Laravel Spectrum** автоматически анализирует контроллеры для генерации документации.
#### AuthController
```php
// app/Http/Controllers/Api/AuthController.php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\LoginRequest;
use App\Http\Requests\RegisterRequest;
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
/**
* Register a new user.
*/
public function register(RegisterRequest $request): JsonResponse
{
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = $user->createToken('auth-token')->plainTextToken;
return response()->json([
'message' => 'User registered successfully',
'user' => new UserResource($user),
'token' => $token,
], 201);
}
/**
* Login user.
*/
public function login(LoginRequest $request): JsonResponse
{
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
return response()->json([
'message' => 'Invalid credentials',
], 401);
}
$token = $user->createToken('auth-token')->plainTextToken;
return response()->json([
'message' => 'Login successful',
'user' => new UserResource($user),
'token' => $token,
]);
}
/**
* Logout user.
*/
public function logout(Request $request): JsonResponse
{
$request->user()->currentAccessToken()->delete();
return response()->json([
'message' => 'Logged out successfully',
]);
}
/**
* Get authenticated user.
*/
public function user(Request $request): JsonResponse
{
return response()->json([
'user' => new UserResource($request->user()),
]);
}
}
```
#### PostController
```php
// app/Http/Controllers/Api/PostController.php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\StorePostRequest;
use App\Http\Requests\UpdatePostRequest;
use App\Http\Resources\PostCollection;
use App\Http\Resources\PostResource;
use App\Models\Post;
use Illuminate\Http\JsonResponse;
class PostController extends Controller
{
/**
* Display a listing of posts.
*/
public function index(): PostCollection
{
$posts = Post::with('user')->latest()->paginate(15);
return new PostCollection($posts);
}
/**
* Store a newly created post.
*/
public function store(StorePostRequest $request): JsonResponse
{
$post = Post::create([
'title' => $request->title,
'content' => $request->content,
'user_id' => $request->user()->id,
]);
$post->load('user');
return response()->json([
'message' => 'Post created successfully',
'post' => new PostResource($post),
], 201);
}
/**
* Display the specified post.
*/
public function show(Post $post): JsonResponse
{
$post->load('user');
return response()->json([
'post' => new PostResource($post),
]);
}
/**
* Update the specified post.
*/
public function update(UpdatePostRequest $request, Post $post): JsonResponse
{
$this->authorize('update', $post);
$post->update($request->validated());
return response()->json([
'message' => 'Post updated successfully',
'post' => new PostResource($post),
]);
}
/**
* Remove the specified post.
*/
public function destroy(Post $post): JsonResponse
{
$this->authorize('delete', $post);
$post->delete();
return response()->json([
'message' => 'Post deleted successfully',
]);
}
}
```
### 3.4 Form Requests
**Laravel Spectrum** автоматически определяет правила валидации из Form Requests.
```php
// app/Http/Requests/RegisterRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RegisterRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
];
}
}
```
```php
// app/Http/Requests/LoginRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class LoginRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'email' => ['required', 'string', 'email'],
'password' => ['required', 'string'],
];
}
}
```
```php
// app/Http/Requests/StorePostRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255'],
'content' => ['required', 'string'],
];
}
}
```
---
## 4. API Endpoints
### 4.1 Маршруты
```php
// routes/api.php
use App\Http\Controllers\Api\AuthController;
use App\Http\Controllers\Api\PostController;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
*/
// Swagger Documentation - редирект на Swagger UI
Route::get('/docs', function () {
return redirect()->to('/spectrum/openapi.html');
});
// Public routes (без авторизации)
Route::post('/register', [AuthController::class, 'register'])->name('api.register');
Route::post('/login', [AuthController::class, 'login'])->name('api.login');
// Protected routes (требуют авторизации)
Route::middleware('auth:sanctum')->group(function () {
// Auth
Route::post('/logout', [AuthController::class, 'logout'])->name('api.logout');
Route::get('/user', [AuthController::class, 'user'])->name('api.user');
// Posts
Route::get('/posts', [PostController::class, 'index'])->name('api.posts.index');
Route::post('/posts', [PostController::class, 'store'])->name('api.posts.store');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('api.posts.show');
Route::put('/posts/{post}', [PostController::class, 'update'])->name('api.posts.update');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('api.posts.destroy');
});
```
### 4.2 Список Endpoints
| Метод | Endpoint | Описание | Авторизация |
|-------|----------|----------|-------------|
| POST | `/api/register` | Регистрация | Нет |
| POST | `/api/login` | Вход | Нет |
| POST | `/api/logout` | Выход | Да |
| GET | `/api/user` | Текущий пользователь | Да |
| GET | `/api/posts` | Список постов | Да |
| POST | `/api/posts` | Создание поста | Да |
| GET | `/api/posts/{id}` | Просмотр поста | Да |
| PUT | `/api/posts/{id}` | Обновление поста | Да |
| DELETE | `/api/posts/{id}` | Удаление поста | Да |
| GET | `/api/docs` | OpenAPI спецификация | Нет |
---
## 5. Использование API
### 5.1 Регистрация
```bash
curl -X POST http://la.test/api/register \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"password": "password123",
"password_confirmation": "password123"
}'
```
### 5.2 Вход
```bash
curl -X POST http://la.test/api/login \
-H "Content-Type: application/json" \
-d '{
"email": "john@example.com",
"password": "password123"
}'
```
### 5.3 Создание поста
```bash
curl -X POST http://la.test/api/posts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {token}" \
-d '{
"title": "My First Post",
"content": "This is the content of my post."
}'
```
### 5.4 Выход
```bash
curl -X POST http://la.test/api/logout \
-H "Authorization: Bearer {token}"
```
---
## 6. Swagger документация
### 6.1 Доступ к документации
Документация Swagger UI доступна по адресу:
```
{APP_URL}/api/docs
```
Например: `http://la.test/api/docs`
### 6.2 Генерация документации
Laravel Spectrum генерирует готовый HTML с Swagger UI:
```bash
php artisan spectrum:generate --format=html
```
Это создаёт файл `public/spectrum/openapi.html`.
### 6.3 Настройка доступа
При генерации с флагом `--format=html` symlink создаётся автоматически.
Если symlink отсутствует, создайте его вручную:
```bash
ln -sf /home/user/www/lara/storage/app/spectrum /home/user/www/lara/public/spectrum
```
### 6.4 Файлы документации
```
public/
└── spectrum/
├── openapi.html # Swagger UI (генерируется с --format=html)
└── openapi.json # OpenAPI спецификация
```
### 6.5 Маршрут для документации
```php
// routes/api.php
// Swagger Documentation
Route::get('/docs', function () {
return redirect()->to('/spectrum/openapi.html');
});
```
---
## 7. Команды Laravel Spectrum
### 7.1 Основные команды
Laravel Spectrum поставляется с готовыми командами для работы с документацией.
| Команда | Описание |
|---------|----------|
| `php artisan spectrum:generate` | Генерация OpenAPI документации |
| `php artisan spectrum:watch` | Режим реального времени (port 8080) |
| `php artisan spectrum:mock` | Запуск mock сервера (port 8081) |
| `php artisan spectrum:cache clear` | Очистка кэша анализа |
### 7.2 Генерация документации
```bash
# Генерация документации в формате HTML
php artisan spectrum:generate --format=html
```
**Вывод:**
```
🚀 Generating API documentation...
🔍 Analyzing routes...
Found 9 API routes
📝 Generating OpenAPI specification...
✅ Documentation generated: /home/user/www/lara/public/spectrum/openapi.html
⏱️ Generation completed in 0.17 seconds
💾 Cache: 5 files, 7.04 KB
✅ Documentation generated successfully!
```
### 7.3 Режим реального времени
```bash
# Запуск режима watch
php artisan spectrum:watch
```
- Запускает локальный сервер на `http://localhost:8080`
- Автоматически обнаруживает изменения в файлах
- Обновляет документацию в реальном времени
### 7.4 Mock сервер
```bash
# Запуск mock API сервера
php artisan spectrum:mock
```
- Запускает mock сервер на `http://localhost:8081`
- Генерирует моковые данные на основе спецификации
- Позволяет тестировать API без реального бэкенда
### 7.5 Обновление документации
После добавления новых endpointов:
```bash
# Очистить кэш и перегенерировать
php artisan spectrum:cache clear
php artisan spectrum:generate
```
---
## 8. Политики доступа
### 8.1 PostPolicy
```php
// app/Policies/PostPolicy.php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
}
```
### 8.2 Регистрация политики
Политики автоматически обнаруживаются Laravel. Для ручной регистрации:
```php
// app/Providers/AuthServiceProvider.php
namespace App\Providers;
use App\Models\Post;
use App\Policies\PostPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
Post::class => PostPolicy::class,
];
public function boot(): void
{
$this->registerPolicies();
}
}
```
---
## 9. Конфигурация .env
```env
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:...
APP_URL=http://la.test
DB_CONNECTION=sqlite
SESSION_DRIVER=database
```
---
## 10. Тестирование
```bash
# Проверка списка маршрутов
php artisan route:list --path=api
# Генерация документации
php artisan spectrum:generate
# Запуск сервера
php artisan serve
```
---
## Troubleshooting
### Проблема: 401 Unauthorized
**Решение:**
1. Проверьте токен в заголовке `Authorization: Bearer {token}`
2. Убедитесь, что используете префикс `Bearer`
### Проблема: 419 CSRF Error
**Решение:**
Уберите `statefulApi()` из middleware в `bootstrap/app.php`:
```php
->withMiddleware(function (Middleware $middleware): void {
// Не используйте statefulApi() для token-based API
})
```
### Проблема: Rate limiter not defined
**Решение:**
Не используйте `throttleApi()`:
```php
// Неправильно
$middleware->throttleApi();
// Правильно (оставить пустым или удалить)
$middleware->api();
```
---
## Заключение
Теперь у вас есть полностью настроенный API с:
-**Laravel Sanctum** - аутентификация через токены
-**wadakatu/laravel-spectrum** - автоматическая генерация Swagger документации
-**API Resources** - форматирование ответов
-**Form Requests** - валидация
-**Swagger документация** - `/api/docs`
**Команды для работы:**
```bash
php artisan spectrum:generate # Генерация документации
php artisan spectrum:watch # Режим разработки
php artisan spectrum:mock # Mock сервер
```
**Документация:** `http://la.test/api/docs`