Урок 08

Аутентификация API: Sanctum

Sanctum — официальный пакет Laravel для аутентификации API. Выдаёт токены, которые клиент отправляет в заголовке Authorization.

Установка

php artisan install:api
php artisan migrate

Модель User

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens;
}

Регистрация

namespace App\Http\Controllers\Api;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $data = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users',
            'password' => ['required', 'confirmed', Password::min(8)],
        ]);

        $user = User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);

        $token = $user->createToken('auth')->plainTextToken;

        return response()->json([
            'user' => $user,
            'token' => $token,
        ], 201);
    }
}

Логин

public function login(Request $request)
{
    $data = $request->validate([
        'email' => 'required|email',
        'password' => 'required',
    ]);

    $user = User::where('email', $data['email'])->first();

    if (!$user || !Hash::check($data['password'], $user->password)) {
        return response()->json(['message' => 'Неверные данные'], 401);
    }

    $token = $user->createToken('auth')->plainTextToken;

    return response()->json([
        'user' => $user,
        'token' => $token,
    ]);
}

Логаут

public function logout(Request $request)
{
    $request->user()->currentAccessToken()->delete();

    return response()->noContent();
}

Защита роутов

Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn (Request $r) => $r->user());
    Route::post('/logout', [AuthController::class, 'logout']);
    Route::apiResource('posts', PostController::class);
});

Отправка токена

Клиент добавляет заголовок:

Authorization: Bearer <token>

Пример:

fetch('/api/posts', {
    headers: {
        Authorization: `Bearer ${token}`,
        Accept: 'application/json',
    },
});

Способности токенов

Можно выдать токен с ограниченными правами:

$token = $user->createToken('api', ['posts:read'])->plainTextToken;

Проверка:

Route::middleware(['auth:sanctum', 'ability:posts:read'])->group(...);

Или в контроллере:

if ($request->user()->tokenCan('posts:read')) {
    //
}