Construirea unui API Laravel Securizat cu Autentificare JWT
Autentificarea JWT (JSON Web Token) în Laravel oferă un mecanism criptografic fără stare, semnat criptografic pentru verificarea consumatorilor API fără stocare de sesiune pe server. Un JWT codifică un payload — de obicei identitatea utilizatorului și revendicările — într-un șir compact, sigur pentru URL, semnat cu un secret sau cheie RSA, permițând oricărui serviciu care deține cheia de verificare să valideze tokenul independent.
Acest ghid acoperă implementarea completă a autentificării JWT într-un API Laravel folosind pachetul `tymon/jwt-auth`, inclusiv configurarea, configurarea modelului, logica controlerului, protecția rutelor, strategia de reîmprospătare a tokenului și întărirea pentru producție. Fiecare pas include context tehnic care depășește tutorialele de nivel superficial.
Cerințe preliminare și ipoteze de mediu
Înainte de a începe, confirmați următoarele:
- PHP 8.1 sau superior (PHP 8.2 recomandat pentru Laravel 11)
- Laravel 10 sau 11 instalat prin Composer
- Composer 2.x
- MySQL 8.0, PostgreSQL 15 sau orice bază de date compatibilă PDO
- Un fișier `.env` configurat cu credențiale `DB_*` valide
- Familiaritate de bază cu containerul de servicii Laravel, middleware și Eloquent ORM
Dacă implementați acest API într-un mediu de producție, un plan de Găzduire VPS cu acces root complet vă oferă controlul necesar pentru a configura PHP-FPM, a gestiona variabilele de mediu în siguranță și a seta corect permisiunile fișierelor — toate esențiale pentru gestionarea secretului JWT.
Pasul 1: Creați un nou proiect Laravel
“`bash
composer create-project laravel/laravel laravel-jwt-api
cd laravel-jwt-api
“`
Verificați instalarea:
“`bash
php artisan –version
“`
Setați cheia aplicației dacă nu a fost generată automat:
“`bash
php artisan key:generate
“`
`APP_KEY` din `.env` este separat de secretul JWT. Ambele sunt necesare și servesc scopuri criptografice diferite — `APP_KEY` protejează cookie-urile criptate și datele de sesiune, în timp ce `JWT_SECRET` semnează tokenii.
Pasul 2: Instalați pachetul de autentificare JWT
Pachetul `tymon/jwt-auth` este standardul de facto pentru JWT în Laravel. Instalați-l:
“`bash
composer require tymon/jwt-auth
“`
Publicați configurația pachetului:
“`bash
php artisan vendor:publish –provider="TymonJWTAuthProvidersLaravelServiceProvider"
“`
Aceasta creează `config/jwt.php`, care controlează TTL-ul tokenului, TTL-ul de reîmprospătare, algoritmul, comportamentul listei negre și revendicările necesare. Examinați cu atenție acest fișier — valorile implicite sunt rezonabile pentru dezvoltare, dar necesită ajustări pentru producție.
Parametrii cheie de configurare în `config/jwt.php`:
| Parametru | Implicit | Recomandare pentru producție |
|---|
| — | — | — |
|---|
| `ttl` | 60 minute | 15–30 minute |
|---|
| `refresh_ttl` | 20160 minute (2 săptămâni) | 1440–10080 minute |
|---|
| `algo` | `HS256` | `RS256` pentru sisteme distribuite |
|---|
| `blacklist_enabled` | `true` | Trebuie să fie `true` |
|---|
| `blacklist_grace_period` | 0 secunde | 10–30 secunde pentru cereri concurente |
|---|
| `required_claims` | `['iss','iat','exp','nbf','sub','jti']` | Păstrați toate; adăugați `aud` pentru API-uri multi-tenant |
|---|
Pasul 3: Generați cheia secretă JWT
“`bash
php artisan jwt:secret
“`
Aceasta adaugă `JWT_SECRET` la fișierul dvs. `.env`. Această valoare este utilizată ca cheie de semnare HMAC-SHA256 pentru toți tokenii când se folosește algoritmul implicit `HS256`.
Note critice de securitate:
- Nu comiteți niciodată `.env` în controlul versiunilor. Adăugați-l imediat la `.gitignore`.
- Pe un pipeline de implementare partajat, injectați `JWT_SECRET` ca variabilă de mediu prin sistemul dvs. CI/CD în loc să îl stocați într-un fișier.
- Dacă rotiți secretul, toți tokenii existenți sunt imediat invalidați. Planificați ferestrele de rotație în consecință și comunicați-le consumatorilor API.
- Pentru arhitecturi de microservicii unde mai multe servicii trebuie să verifice tokenii, treceți la `RS256`. Generați o pereche de chei RSA, stocați cheia privată pe serviciul de autentificare și distribuiți doar cheia publică serviciilor consumatoare.
Pasul 4: Configurați garda de autentificare
Deschideți `config/auth.php` și actualizați secțiunile defaults și guards:
“`php
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
“`
Aceasta instruiește sistemul de autentificare Laravel să utilizeze driverul JWT la rezolvarea gărzii `api`. Middleware-ul `auth:api` va delega acum validarea tokenului către `tymon/jwt-auth` în loc de Laravel Passport sau driverul implicit de token.
Nu eliminați garda `web`. Multe componente interne Laravel depind de ea, iar eliminarea ei cauzează eșecuri neașteptate în comenzile consolei și lucrătorii de coadă care interacționează cu sistemul de autentificare.
Pasul 5: Creați modelul User și migrarea
Dacă modelul implicit `User` și migrarea există deja (există într-o instalare Laravel nouă), le puteți modifica direct. Dacă începeți de la zero:
“`bash
php artisan make:model User -m
“`
Deschideți fișierul de migrare din `database/migrations/` și definiți schema:
“`php
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
“`
Rulați migrarea:
“`bash
php artisan migrate
“`
Notă pentru producție: Rulați întotdeauna migrările cu indicatorul `–force` în mediile de producție unde `APP_ENV=production`, deoarece Laravel va solicita confirmare altfel:
“`bash
php artisan migrate –force
“`
Pasul 6: Implementați interfața JWTSubject în modelul User
Pachetul `tymon/jwt-auth` necesită ca modelul dvs. autentificabil să implementeze contractul `JWTSubject`. Deschideți `app/Models/User.php`:
“`php
<?php
namespace AppModels;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateFoundationAuthUser as Authenticatable;
use IlluminateNotificationsNotifiable;
use TymonJWTAuthContractsJWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
/**
- Get the identifier that will be stored in the JWT subject claim.
*/
public function getJWTIdentifier(): mixed
{
return $this->getKey();
}
/**
- Return a key-value array of arbitrary claims to add to the JWT payload.
*/
public function getJWTCustomClaims(): array
{
return [];
}
}
“`
Despre revendicările personalizate: Metoda `getJWTCustomClaims()` este locul unde încorporați date specifice aplicației direct în payload-ul tokenului. Cazurile de utilizare comune includ încorporarea `role`, `tenant_id` sau `permissions` astfel încât serviciile din aval să poată lua decizii de autorizare fără o interogare a bazei de date. Fiți deliberat cu privire la ce încorporați — fiecare revendicare crește dimensiunea tokenului și este lizibilă de oricine decodifică base64 payload-ul. Nu încorporați niciodată date sensibile precum parole sau PII.
Pasul 7: Construiți controlerul de autentificare
“`bash
php artisan make:controller AuthController
“`
Completați `app/Http/Controllers/AuthController.php` cu logica completă de autentificare:
“`php
<?php
namespace AppHttpControllers;
use AppModelsUser;
use IlluminateHttpJsonResponse;
use IlluminateHttpRequest;
use IlluminateSupportFacadesAuth;
use IlluminateSupportFacadesHash;
use IlluminateValidationValidationException;
use TymonJWTAuthExceptionsJWTException;
use TymonJWTAuthFacadesJWTAuth;
class AuthController extends Controller
{
/**
- Register a new user and return a JWT.
*/
public function register(Request $request): JsonResponse
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
]);
$user = User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => Hash::make($validated['password']),
]);
$token = JWTAuth::fromUser($user);
return response()->json([
'token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60,
], 201);
}
/**
- Authenticate a user and return a JWT.
*/
public function login(Request $request): JsonResponse
{
$credentials = $request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
]);
if (!$token = Auth::guard('api')->attempt($credentials)) {
return response()->json(['error' => 'Invalid credentials'], 401);
}
return $this->respondWithToken($token);
}
/**
- Invalidate the current token (logout).
*/
public function logout(): JsonResponse
{
try {
Auth::guard('api')->logout();
} catch (JWTException $e) {
return response()->json(['error' => 'Failed to invalidate token'], 500);
}
return response()->json(['message' => 'Successfully logged out']);
}
/**
- Refresh the current token.
*/
public function refresh(): JsonResponse
{
try {
$token = Auth::guard('api')->refresh();
} catch (JWTException $e) {
return response()->json(['error' => 'Token cannot be refreshed'], 401);
}
return $this->respondWithToken($token);
}
/**
- Return the authenticated user's profile.
*/
public function me(): JsonResponse
{
return response()->json(Auth::guard('api')->user());
}
/**
- Format the token response consistently.
*/
protected function respondWithToken(string $token): JsonResponse
{
return response()->json([
'token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60,
]);
}
}
“`
De ce contează specificarea explicită a gărzii: Apelarea `Auth::attempt()` fără specificarea gărzii revine la garda implicită. Dacă ați schimbat implicit la `api`, aceasta funcționează — dar este fragil. Apelați întotdeauna `Auth::guard('api')->attempt()` explicit pentru a evita erori subtile când garda implicită se schimbă în timpul refactorizării.
Pasul 8: Definiți rutele API
Deschideți `routes/api.php` și definiți rutele de autentificare și cele protejate:
“`php
<?php
use AppHttpControllersAuthController;
use IlluminateSupportFacadesRoute;
// Public authentication routes
Route::prefix('auth')->group(function () {
Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);
});
// Protected routes — require a valid JWT
Route::middleware('auth:api')->prefix('auth')->group(function () {
Route::post('logout', [AuthController::class, 'logout']);
Route::post('refresh', [AuthController::class, 'refresh']);
Route::get('me', [AuthController::class, 'me']);
});
// Example protected resource routes
Route::middleware('auth:api')->group(function () {
Route::apiResource('posts', AppHttpControllersPostController::class);
});
“`
Strategia prefixului de rută: Gruparea endpoint-urilor de autentificare sub `/api/auth/` este o convenție larg adoptată care face documentația API mai curată și simplifică regulile de limitare a ratei — puteți aplica o limitare mai strictă la `/api/auth/login` independent de endpoint-urile de resurse.
Pasul 9: Protejarea rutelor și gestionarea eșecurilor middleware
Middleware-ul `auth:api` din Laravel va returna un răspuns `401 Unauthenticated` când un token lipsește, a expirat sau este invalid. Pentru a returna un răspuns JSON consistent în loc de o redirecționare HTML, suprascrieți metoda `unauthenticated` în `app/Exceptions/Handler.php`:
“`php
use IlluminateAuthAuthenticationException;
use IlluminateHttpRequest;
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson() || $request->is('api/*')) {
return response()->json(['error' => 'Unauthenticated'], 401);
}
return redirect()->guest(route('login'));
}
“`
Fără această suprascriere, clienții API primesc o redirecționare HTML 302 către o pagină de autentificare care nu există într-o aplicație API pură — o sursă comună de confuzie în timpul testării de integrare.
Pasul 10: Strategia de reîmprospătare a tokenului și lista neagră
Natura fără stare a JWT creează o tensiune: tokenii sunt autonomi și valizi până la expirare, dar aveți nevoie de o modalitate de a-i revoca la deconectare. Pachetul `tymon/jwt-auth` rezolvă aceasta cu o listă neagră de tokeni susținută de driverul de cache Laravel.
Cum funcționează lista neagră:
- La deconectare, revendicarea `jti` (JWT ID) a tokenului este stocată în cache cu un TTL corespunzând duratei de viață rămase a tokenului.
- La fiecare cerere autentificată, middleware-ul verifică lista neagră înainte de a accepta tokenul.
- Setarea `blacklist_grace_period` permite o fereastră scurtă în care un token care este reîmprospătat poate fi în continuare utilizat, prevenind condițiile de cursă în clienții care fac cereri concurente.
Asigurați-vă că driverul dvs. de cache suportă aceasta. Driverul implicit `file` funcționează pentru implementări pe un singur server. Pentru API-uri scalate orizontal care rulează pe mai multe noduri — comune când se utilizează Servere Dedicate într-o configurație cu echilibrare de sarcină — treceți la Redis sau Memcached:
“`env
CACHE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
“`
Fluxul de reîmprospătare a tokenului:
“`
Client API Server
| — POST /api/auth/refresh ——> |
|---|
| Authorization: Bearer <old> |
|---|
| — Validate old token |
|---|
| — Blacklist old token's jti |
|---|
| — Issue new token |
|---|
| <– 200 { token: <new> } ——– |
|---|
“`
Tokenul vechi este imediat adăugat pe lista neagră la reîmprospătare. Clienții trebuie să stocheze noul token și să îl elimine pe cel vechi. Implementați aceasta ca un interceptor Axios sau echivalent în frontend-ul dvs. pentru a gestiona reîmprospătarea tokenului în mod transparent.
Pasul 11: Testarea API-ului
Utilizați `curl` sau Postman pentru a verifica fiecare endpoint.
Înregistrați un utilizator:
“`bash
curl -X POST https://your-domain.com/api/auth/register
-H "Content-Type: application/json"
-d '{
"name": "Jane Smith",
"email": "jane@example.com",
"password": "SecurePass123!",
"password_confirmation": "SecurePass123!"
}'
“`
Răspuns așteptat (`201 Created`):
“`json
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…",
"token_type": "bearer",
"expires_in": 3600
}
“`
Autentificați-vă:
“`bash
curl -X POST https://your-domain.com/api/auth/login
-H "Content-Type: application/json"
-d '{"email": "jane@example.com", "password": "SecurePass123!"}'
“`
Accesați o rută protejată:
“`bash
curl -X GET https://your-domain.com/api/auth/me
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…"
“`
Reîmprospătați tokenul:
“`bash
curl -X POST https://your-domain.com/api/auth/refresh
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…"
“`
Deconectați-vă:
“`bash
curl -X POST https://your-domain.com/api/auth/logout
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…"
“`
JWT vs. Sesiune vs. Laravel Sanctum vs. Passport
Înțelegerea momentului în care JWT este alegerea potrivită necesită compararea cu alternativele disponibile în ecosistemul Laravel.
| Criteriu | JWT (`tymon/jwt-auth`) | Laravel Sanctum | Laravel Passport | Bazat pe sesiune |
|---|
| — | — | — | — | — |
|---|
| **Stare** | Fără stare | Fără stare (tokeni SPA) / Cu stare (cookie-uri) | Cu stare (tokeni DB) | Cu stare |
|---|
| **Stocare token** | Pe client | Pe client sau cookie | Bază de date | Sesiune pe server |
|---|
| **Revocare** | Listă neagră (cache) | Imediată (ștergere DB) | Imediată (ștergere DB) | Imediată |
|---|
| **Scalabilitate** | Excelentă (fără DB per cerere) | Bună | Moderată (interogare DB per cerere) | Slabă (sincronizare sesiune necesară) |
|---|
| **Suport OAuth2** | Nu | Nu | Da (server OAuth2 complet) | Nu |
|---|
| **Complexitate** | Medie | Scăzută | Ridicată | Scăzută |
|---|
| **Cel mai bun pentru** | API-uri fără stare, microservicii | SPA-uri, aplicații mobile | Clienți OAuth terți | Aplicații web tradiționale |
|---|
| **Introspecție token** | Decodificați payload-ul pe client | Necesită apel API | Necesită apel API | N/A |
|---|
Când să alegeți JWT în locul Sanctum: Dacă API-ul dvs. este consumat de clienți terți, aplicații mobile sau microservicii care nu pot partaja un cookie de sesiune sau o conexiune la baza de date cu aplicația dvs. Laravel, natura autonomă a JWT este un avantaj semnificativ. Dacă construiți un SPA propriu pe același domeniu, Sanctum cu autentificare bazată pe cookie-uri este mai simplu și evită complet problemele de securitate ale stocării tokenului.
Întărirea securității pentru producție
O implementare JWT funcțională nu este implicit una sigură. Aplicați aceste măsuri de întărire înainte de lansare:
1. Impuneți HTTPS necondiționat
Tokenii JWT transmisi prin HTTP sunt interceptabili trivial. Impuneți TLS la nivelul serverului web și redirecționați tot traficul HTTP. Combinați aceasta cu un Certificat SSL pentru a asigura transport criptat pentru fiecare cerere API.
2. Setați TTL-uri agresive pentru tokeni
Tokenii de acces cu durată scurtă (15–30 minute) combinați cu tokeni de reîmprospătare cu durată mai lungă (7–14 zile) limitează impactul unui token furat. Actualizați `config/jwt.php`:
“`php
'ttl' => 15,
'refresh_ttl' => 10080,
“`
3. Aplicați limitarea ratei la endpoint-urile de autentificare
Middleware-ul throttle integrat în Laravel previne atacurile prin forță brută:
“`php
Route::middleware(['throttle:10,1'])->group(function () {
Route::post('auth/login', [AuthController::class, 'login']);
Route::post('auth/register', [AuthController::class, 'register']);
});
“`
Aceasta limitează fiecare IP la 10 cereri pe minut pe endpoint-urile de autentificare.
4. Validați revendicarea `aud` pentru API-uri multi-tenant
Dacă API-ul dvs. deservește mai multe aplicații client, încorporați și validați o revendicare `audience` pentru a preveni reutilizarea tokenului între servicii:
“`php
// In getJWTCustomClaims()
return [
'aud' => config('app.jwt_audience'),
];
“`
5. Protejați JWT_SECRET la nivelul OS
Setați permisiuni restrictive pentru fișiere pe `.env`:
“`bash
chmod 640 .env
chown www-data:www-data .env
“`
Pe un VPS cu cPanel configurat corespunzător, puteți gestiona proprietatea și permisiunile fișierelor prin File Manager sau SSH fără riscul de a expune secretele altor utilizatori de pe sistem.
6. Înregistrați evenimentele de autentificare
Integrați sistemul de evenimente Laravel pentru a înregistra tentativele de autentificare eșuate, reîmprospătările de token și deconectările într-un serviciu de înregistrare centralizat. Aceasta este esențială pentru detectarea anomaliilor.
Adăugarea controlului accesului bazat pe roluri
Revendicările personalizate fac simplu să încorporați roluri direct în token:
“`php
// In User model
public function getJWTCustomClaims(): array
{
return [
'role' => $this->role, // e.g., 'admin', 'editor', 'viewer'
];
}
“`
Creați un middleware pentru a impune cerințele de rol:
“`php
<?php
namespace AppHttpMiddleware;
use Closure;
use IlluminateHttpRequest;
use TymonJWTAuthFacadesJWTAuth;
class RoleMiddleware
{
public function handle(Request $request, Closure $next, string $role): mixed
{
$payload = JWTAuth::parseToken()->getPayload();
if ($payload->get('role') !== $role) {
return response()->json(['error' => 'Forbidden'], 403);
}
return $next($request);
}
}
“`
Înregistrați-l în `app/Http/Kernel.php` (Laravel 10) sau `bootstrap/app.php` (Laravel 11) și aplicați-l la rute:
“`php
Route::middleware(['auth:api', 'role:admin'])->group(function () {
Route::apiResource('admin/users', AdminUserController::class);
});
“`
Avertisment: Datele de rol încorporate în token sunt doar atât de actuale cât este tokenul însuși. Dacă rolul unui utilizator se schimbă, tokenul vechi continuă să acorde rolul vechi până când expiră sau este reîmprospătat. Pentru schimbări de rol cu securitate ridicată (de exemplu, revocarea imediată a accesului de administrator), combinați lista neagră a tokenului cu un TTL scurt sau efectuați o verificare a rolului în baza de date în middleware alături de verificarea revendicării.
Considerații de implementare pentru API-urile Laravel JWT
La trecerea de la dezvoltarea locală la un server de producție, mai mulți factori specifici mediului afectează comportamentul JWT:
- Consistența fusului orar: Revendicările `iat`, `nbf` și `exp` JWT sunt timestamp-uri Unix. Asigurați-vă că fusul orar al serverului este setat la UTC (`date.timezone = UTC` în `php.ini`) pentru a preveni respingerea tokenului din cauza decalajului de ceas.
- OPcache: Activați PHP OPcache pentru a reduce suprasarcina încărcării fișierelor bibliotecii JWT la fiecare cerere. Aceasta are un impact deosebit pe API-urile cu trafic ridicat.
- Lucrători de coadă pentru curățarea tokenului: Dacă implementați joburi personalizate de curățare a listei negre a tokenului, asigurați-vă că lucrătorul de coadă rulează ca un proces supravegheat (Supervisor sau systemd).
- Gestionarea variabilelor de mediu: Pe Panouri de Control VPS, utilizați managerul de variabile de mediu al panoului în loc să editați direct `.env` în producție, pentru a evita suprascrierile accidentale în timpul implementărilor.
Listă de verificare înainte de lansare
Utilizați această listă de verificare pentru a confirma că implementarea dvs. este pregătită pentru producție:
- `JWT_SECRET` are cel puțin 32 de caractere, generat aleatoriu și nu este comis în controlul versiunilor
- `blacklist_enabled` este setat la `true` în `config/jwt.php`
- TTL-ul tokenului este de 30 de minute sau mai puțin pentru tokenii de acces
- TTL-ul de reîmprospătare este setat la o valoare adecvată politicii dvs. de sesiune
- Toate endpoint-urile API sunt servite exclusiv prin HTTPS
- Limitarea ratei este aplicată endpoint-urilor `/login` și `/register`
- Gestionarul de excepții `unauthenticated` returnează JSON, nu o redirecționare HTML
- Revendicările personalizate nu conțin parole, secrete sau PII sensibil
- Driverul de cache este Redis sau Memcached (nu `file`) în implementările pe mai multe servere
- Evenimentele de autentificare sunt înregistrate și monitorizate
- Schimbările de rol care necesită efect imediat sunt gestionate prin lista neagră, nu doar prin expirarea revendicării
- Permisiunile fișierului `.env` sunt restricționate la utilizatorul serverului web
Întrebări frecvente
Care este diferența dintre `JWT_SECRET` și `APP_KEY` în Laravel?
`APP_KEY` este utilizat de serviciul de criptare Laravel pentru criptarea cookie-urilor, datelor de sesiune și valorilor transmise prin `Crypt::encrypt()`. `JWT_SECRET` este utilizat exclusiv de `tymon/jwt-auth` pentru a semna și verifica JSON Web Token-urile. Sunt independente criptografic și servesc scopuri complet diferite. Ambele trebuie păstrate secrete.
De ce tokenul meu JWT continuă să returneze 401 chiar dacă nu a expirat?
Cele mai comune cauze sunt: tokenul a fost adăugat pe lista neagră (de exemplu, după o deconectare sau reîmprospătare), `JWT_SECRET` a fost rotat după emiterea tokenului, driverul de cache care stochează lista neagră este indisponibil sau există un decalaj de ceas între serverul emitent și serverul de validare care depășește setarea `leeway` din `config/jwt.php`. Verificați fiecare dintre acestea în ordine.
Pot utiliza autentificarea JWT cu cozile Laravel sau comenzile consolei?
JWT este conceput pentru autentificarea cererilor HTTP. În interiorul joburilor de coadă sau comenzilor Artisan, nu există context de cerere HTTP, deci nu puteți rezolva un utilizator dintr-un token prin middleware. În schimb, transmiteți cheia primară a utilizatorului ca parametru al jobului și încărcați modelul direct cu `User::find($userId)`.
Cum gestionez cererile concurente în timpul reîmprospătării tokenului fără a obține erori 401?
Setați `blacklist_grace_period` în `config/jwt.php` la o valoare între 10 și 30 de secunde. În această fereastră, un token care tocmai a fost reîmprospătat (și tehnic adăugat pe lista neagră) va fi în continuare acceptat. Aceasta previne condițiile de cursă în clienții care trimit mai multe cereri simultane în timp ce o reîmprospătare este în curs.
Este `tymon/jwt-auth` compatibil cu Laravel 11?
Începând cu ciclul de lansare curent, versiunea `tymon/jwt-auth` `2.x` suportă Laravel 10 și 11 prin ramura `dev-develop` sau lansările etichetate care declară compatibilitate. Verificați întotdeauna constrângerile `composer.json` ale pachetului și tracker-ul de probleme GitHub înainte de a actualiza versiunile Laravel într-un proiect care depinde de acest pachet. Luați în considerare fixarea versiunii pachetului în `composer.json` pentru a evita modificările neașteptate în timpul `composer update`.
