Ответ
JWT (JSON Web Token) — стандартный способ передачи claims между сторонами в виде подписанного JSON-объекта. В .NET для работы с JWT используется пакет System.IdentityModel.Tokens.Jwt.
1. Генерация Access Token Токен создается на сервере аутентификации после успешной проверки учетных данных.
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
public string GenerateJwtToken(string userId, string email, List<string> roles)
{
// 1. Подготовка секретного ключа (в продакшене храните в безопасном месте, например, в Azure Key Vault)
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Secret"]));
var signingCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
// 2. Формирование claims (утверждений о пользователе)
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, userId), // Subject (идентификатор пользователя)
new Claim(JwtRegisteredClaimNames.Email, email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) // Unique token ID
};
// Добавление ролей как отдельных claims (стандарт для ASP.NET Core)
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
// 3. Создание самого токена
var token = new JwtSecurityToken(
issuer: _configuration["Jwt:Issuer"], // Кто выдал
audience: _configuration["Jwt:Audience"], // Для кого предназначен
claims: claims,
expires: DateTime.UtcNow.AddMinutes(15), // Короткое время жизни Access Token
signingCredentials: signingCredentials
);
// 4. Кодирование токена в строку
return new JwtSecurityTokenHandler().WriteToken(token);
}
2. Валидация токена в API
В ASP.NET Core валидация настраивается централизованно в Program.cs или Startup.cs.
// Конфигурация аутентификации
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidateAudience = true,
ValidAudience = builder.Configuration["Jwt:Audience"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"])
),
ValidateLifetime = true, // Проверять срок действия
ClockSkew = TimeSpan.Zero // Не давать "форы" по времени (опционально)
};
// Для Bearer-токенов из заголовка Authorization этого достаточно.
// Для токенов из кук или query-строки настройте options.Events.
});
// Затем используйте атрибут [Authorize] на контроллерах или методах.
3. Refresh Token Механизм
Access Token короткоживущий, Refresh Token — долгоживущий (дни, недели), хранится безопасно (в HttpOnly куке или БД) и используется для получения новой пары токенов.
// Генерация Refresh Token (случайная строка, сохраненная в БД с привязкой к userId)
public string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
// Эндпоинт для обновления токенов
[HttpPost("refresh-token")]
public async Task<IActionResult> RefreshToken(RefreshTokenRequest request)
{
// 1. Валидируем старый Access Token (даже истекший) чтобы извлечь userId
// 2. Проверяем, что переданный Refresh Token существует и активен для этого userId в БД
// 3. Если все ок, генерируем новую пару Access/Refresh токенов
// 4. Старый Refresh Token инвалидируем (удаляем или помечаем использованным)
// 5. Возвращаем новые токены клиенту
}
4. Критически важные практики безопасности:
- Никогда не храните секретный ключ (Secret) в коде. Используйте менеджеры секретов (Azure Key Vault, HashiCorp Vault) или переменные окружения.
- Используйте HTTPS (TLS) всегда. JWT передается открытым текстом.
- Храните Refresh Tokens безопасно:
HttpOnly,Secure,SameSite=Strictкуки — лучший вариант для веб-приложений. - Реализуйте отзыв токенов (token revocation): Вести черный список отозванных токенов (по
jti) или инвалидировать все токены пользователя при смене пароля. - Ограничивайте claims: Не помещайте в токен чувствительные данные (пароли).