Введение в OAuth 2.0 и JWT на C#
Современные веб-приложения требуют надежных механизмов безопасности. Два ключевых протокола — OAuth 2.0 и JWT (JSON Web Token) — стали стандартом де-факто для реализации авторизации и аутентификации. В этой статье мы разберем, как использовать эти технологии в экосистеме C# (.NET).
OAuth 2.0 — это протокол делегированного доступа, который позволяет приложениям получать ограниченный доступ к ресурсам пользователя без передачи его учетных данных. JWT, в свою очередь, представляет собой компактный и самодостаточный формат токенов, который часто используется для передачи информации об аутентификации между клиентом и сервером.
В этом руководстве мы создадим простое веб-API на ASP.NET Core, реализующее OAuth 2.0 с использованием JWT-токенов. Вы узнаете, как настроить генерацию, валидацию и защиту эндпоинтов.
Что такое OAuth 2.0 и JWT?
Прежде чем перейти к коду, давайте разберем основные концепции.
OAuth 2.0
OAuth 2.0 определяет четыре роли:
- Resource Owner (владелец ресурса) — обычно пользователь.
- Client (клиент) — приложение, которое хочет получить доступ.
- Authorization Server (сервер авторизации) — выдает токены.
- Resource Server (сервер ресурсов) — предоставляет защищенные данные.
Основной поток Authorization Code Grant включает: перенаправление пользователя на сервер авторизации, получение кода, обмен кода на токен доступа.
JWT (JSON Web Token)
JWT состоит из трех частей, разделенных точками:
- Header — тип токена и алгоритм подписи (например, HS256).
- Payload — данные (claims), такие как ID пользователя, роль, срок действия.
- Signature — подпись, созданная с помощью секретного ключа.
Пример JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Настройка проекта ASP.NET Core
Создадим новый проект веб-API с поддержкой аутентификации.
dotnet new webapi -n OAuthJwtDemo
cd OAuthJwtDemo
Добавим необходимые NuGet-пакеты:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package System.IdentityModel.Tokens.Jwt
Конфигурация в appsettings.json
Добавьте секцию для JWT-настроек в файл appsettings.json:
{
"JwtSettings": {
"SecretKey": "YOUR_SUPER_SECRET_KEY_AT_LEAST_32_CHARS",
"Issuer": "OAuthJwtDemo",
"Audience": "OAuthJwtDemoClient",
"ExpirationMinutes": 60
}
}
Важно: В реальном проекте храните секретный ключ в User Secrets или Azure Key Vault.
Реализация сервиса генерации JWT
Создадим интерфейс и его реализацию для работы с токенами.
Интерфейс IJwtService
public interface IJwtService
{
string GenerateToken(string userId, string role);
ClaimsPrincipal ValidateToken(string token);
}
Реализация JwtService
public class JwtService : IJwtService
{
private readonly JwtSettings _settings;
public JwtService(IOptions<JwtSettings> settings)
{
_settings = settings.Value;
}
public string GenerateToken(string userId, string role)
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, userId),
new Claim(ClaimTypes.Role, role),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_settings.SecretKey));
var credentials = new SigningCredentials(key,
SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _settings.Issuer,
audience: _settings.Audience,
claims: claims,
expires: DateTime.UtcNow.AddMinutes(_settings.ExpirationMinutes),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public ClaimsPrincipal ValidateToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes(_settings.SecretKey);
var principal = tokenHandler.ValidateToken(token,
new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = _settings.Issuer,
ValidAudience = _settings.Audience,
IssuerSigningKey = new SymmetricSecurityKey(key)
}, out _);
return principal;
}
}
Настройка аутентификации в Program.cs
В файле Program.cs настройте сервисы и middleware:
// Регистрация сервисов
builder.Services.Configure<JwtSettings>(
builder.Configuration.GetSection("JwtSettings"));
builder.Services.AddScoped<IJwtService, JwtService>();
// Настройка аутентификации
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme =
JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
var jwtSettings = builder.Configuration
.GetSection("JwtSettings").Get<JwtSettings>();
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings.Issuer,
ValidAudience = jwtSettings.Audience,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtSettings.SecretKey))
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();