Ответ
JWT — это открытый стандарт (RFC 7519) для создания токенов доступа, которые позволяют безопасно передавать информацию между сторонами в виде компактного JSON-объекта. Токен подписан цифровой подписью, что позволяет проверять его целостность и подлинность.
Структура JWT: Токен состоит из трех частей, разделенных точками:
header.payload.signature
- Header (Заголовок): Содержит тип токена (
JWT) и алгоритм подписи (например,HS256илиRS256).{ "alg": "HS256", "typ": "JWT" } - Payload (Полезная нагрузка): Содержит утверждения (claims) — утверждения о пользователе и дополнительных данных. Стандартные claims:
sub(subject — идентификатор пользователя),exp(expiration time — срок действия),iat(issued at — время выдачи).{ "sub": "1234567890", "name": "John Doe", "role": "admin", "exp": 1516239022 } - Signature (Подпись): Создается путем кодирования header и payload в Base64Url, их объединения с точкой и последующей подписи с использованием секретного ключа (для HMAC) или приватного ключа (для RSA) по алгоритму, указанному в header.
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
Типичный поток аутентификации с JWT:
- Логин: Пользователь отправляет учетные данные (логин/пароль) на сервер аутентификации.
- Верификация и генерация токена: Сервер проверяет учетные данные и, если они верны, генерирует JWT, подписывает его секретным ключом и отправляет клиенту (обычно в теле ответа или в cookie).
- Хранение и отправка токена: Клиент (браузер, мобильное приложение) сохраняет токен (часто в
localStorageилиHttpOnlycookie) и включает его в заголовокAuthorizationпоследующих запросов к защищенным API.Authorization: Bearer <your-jwt-token> - Верификация токена на защищенных ресурсах: Сервер (или API-шлюз) получает токен, проверяет его подпись на валидность с помощью секретного/публичного ключа, убеждается, что срок действия (
exp) не истек, и извлекает claims (например,role) для авторизации доступа к ресурсу.
Ключевые преимущества:
- Бессостояние (Stateless): Серверу не нужно хранить сессию пользователя. Вся необходимая информация содержится в самом токене.
- Масштабируемость: Легко масштабировать, так как любой сервер с секретным/публичным ключом может проверить токен.
- Гибкость: В payload можно включать любые пользовательские данные (claims).
Критические моменты безопасности:
- Секретный ключ: Должен храниться в безопасности на сервере. Компрометация ключа позволяет злоумышленнику генерировать любые токены.
- Небезопасное хранение на клиенте: Хранение в
localStorageуязвимо к XSS-атакам. Более безопасный вариант —HttpOnly,Secure,SameSitecookies. - Невозможность отзыва: JWT действует до истечения срока (
exp). Для реализации мгновенного выхода (logout) требуется дополнительная архитектура (черные списки токенов, короткий срок жизни + refresh tokens).
Пример генерации и проверки токена на C# (библиотека System.IdentityModel.Tokens.Jwt):
// Генерация токена
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_super_secret_key"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, "user123"),
new Claim("role", "admin")
};
var token = new JwtSecurityToken(
issuer: "your_issuer",
audience: "your_audience",
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: credentials
);
var tokenString = new JwtSecurityTokenHandler().WriteToken(token);
// Проверка токена
var tokenHandler = new JwtSecurityTokenHandler();
tokenHandler.ValidateToken(tokenString, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = securityKey,
ValidateIssuer = true,
ValidIssuer = "your_issuer",
ValidateAudience = true,
ValidAudience = "your_audience",
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero // Точная проверка времени
}, out SecurityToken validatedToken);