Ответ
JSON Web Token (JWT) — это компактный, URL-безопасный способ представления claims (утверждений), которые передаются между двумя сторонами. Он состоит из трёх частей (Header.Payload.Signature), подписанных цифровой подписью.
Преимущества:
- Stateless (без состояния): Серверу не нужно хранить сессию пользователя в памяти или БД. Вся необходимая информация содержится в самом токене, что упрощает масштабирование.
- Самостоятельность (Self-contained): Токен может содержать основные claims (например,
userId,roles), что уменьшает количество запросов к БД для проверки прав. - Универсальность: Легко используется в различных клиентах (веб, мобильные приложения, микросервисы) и протоколах (REST/GraphQL).
- Цифровая подпись: Гарантирует целостность данных. Изменение payload или header инвалидирует подпись.
Недостатки и риски:
- Немедленный отзыв (Revocation): Основная проблема. Токен валиден до истечения срока его жизни (
exp). Для принудительного отзыва приходится использовать чёрные списки токенов (что нарушает stateless-принцип) или очень короткие сроки жизни с обновлением через refresh-токены. - Размер: JWT больше, чем обычный идентификатор сессии. При каждом запросе он передаётся в заголовке
Authorization, увеличивая трафик. - Хранение на клиенте: Уязвим к атакам XSS, если хранится в
localStorage. Безопаснее хранить вHttpOnlycookie, но это усложняет использование для нативных мобильных приложений. - Не шифрование по умолчанию: JWT только подписан (JWS), но не зашифрован (JWE). Конфиденциальные данные в payload видны всем, кто получит токен (используйте JWE или не кладите такие данные).
Пример создания и валидации в .NET:
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
// Создание токена
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_super_secret_key"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("sub", "user123"),
new Claim("role", "Admin")
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = credentials,
Issuer = "your-api"
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var jwtString = tokenHandler.WriteToken(token);
// Валидация токена в Middleware (Program.cs)
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "your-api",
ValidateAudience = false, // Или установите свою аудиторию
ValidateLifetime = true,
IssuerSigningKey = securityKey
};
});
Когда использовать: JWT идеален для stateless API, микросервисной архитектуры и single-page applications. Для традиционных веб-приложений с серверным рендерингом часто предпочтительнее классические cookie-сессии.
Ответ 18+ 🔞
Ну, вот смотри, есть такая штука — JWT. Это, по сути, такая бумажка, но цифровая. В ней три части, склеенные точками: заголовок, полезная нагрузка и подпись. Как будто паспорт, но для твоего API. Написал там, кто ты и на что имеешь право, подписал секретным ключом — и пошёл гулять по эндпоинтам.
Что в нём хорошего, спросишь?
- Без состояния (Stateless): Серверу похуй, он тебя не помнит. Вся твоя биография в самой этой бумажке. Нет сессий в памяти — масштабируйся на здоровье, хоть на тысячу инстансов.
- Самостоятельный: Внутри уже может лежать твой
userIdи то, что ты там,Admin. Не надо при каждом чихе бегать в базу и спрашивать «а можно ему?». - Универсальный: Засунь его в заголовок запроса из браузера, из мобилы, из другого микросервиса — везде сработает.
- Подписанный: Попробуй там в
payloadчто-то подправить на ходу — подпись ебнется, и все сразу поймут, что ты мудак.
А теперь про подводные грабли, потому что нихуя не всё так радужно:
- Отозвать — та ещё задача: Пока у токена срок годности не вышел (
exp), он жив. Хоть ты уволился, хоть пароль сменил. Чтобы прибить его досрочно, приходится заводить чёрный список, а это уже нарушение священного принципа «без состояния». Либо крутить refresh-токены с короткой жизнью, что тоже весело. - Раздутый: Он, сука, больше, чем просто
sessionId. И таскать его в каждом запросе в заголовкеAuthorization— лишний трафик. Не критично, но приятного мало. - Где хранить — головная боль: Положил в
localStorage— получи XSS-уязвимость, любой скрипт его вытащит. Класть вHttpOnlyкуки безопаснее, но тогда для нативных мобильных приложений начинается геморрой. - Он не шифрованный по дефолту! Это важно, ёпта! JWT (JWS) только подписан, но не зашифрован. Все, кто перехватят токен, увидят твой
payloadкак на ладони. Не суй туда пароли, номера карт и размер члена. Для этого есть JWE, или просто не клади туда то, что не должен видеть посторонний.
Вот, смотри, как на .NET с ним возиться:
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
// Делаем токен
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_super_secret_key"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("sub", "user123"),
new Claim("role", "Admin")
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = credentials,
Issuer = "your-api"
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var jwtString = tokenHandler.WriteToken(token);
// А вот так его проверяем (в Program.cs)
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "your-api",
ValidateAudience = false, // Или поставь true, если аудитория нужна
ValidateLifetime = true,
IssuerSigningKey = securityKey
};
});
Итог: JWT — офигенная штука для stateless API, микросервисов и SPA. Но если у тебя обычное веб-приложение с рендерингом на сервере, то, может, проще со старыми добрыми куками-сессиями не выёбываться? Выбор за тобой, чувак.