OAuth 2.0 и JWT авторизация на C#: Полное руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в OAuth 2.0 и JWT на C#

Современные веб-приложения и API требуют надежной системы авторизации. Два самых популярных стандарта — OAuth 2.0 (протокол делегирования доступа) и JWT (JSON Web Token, формат токена) — стали основой безопасности в экосистеме .NET. В этой статье мы разберем, как реализовать OAuth 2.0 и JWT авторизацию на C# в ASP.NET Core, создадим пример сервера авторизации и защитим API.

Независимо от того, создаете ли вы монолитное приложение или микросервисную архитектуру, понимание этих механизмов критически важно. OAuth 2.0 определяет роли (клиент, сервер авторизации, ресурсный сервер), а JWT служит компактным и самодостаточным способом передачи данных о пользователе.

Основы OAuth 2.0: потоки и роли

Что такое OAuth 2.0?

OAuth 2.0 — это протокол авторизации, который позволяет сторонним приложениям получать ограниченный доступ к ресурсам пользователя без передачи его учетных данных. Вместо логина и пароля используются токены доступа (access tokens).

Основные роли в OAuth 2.0

  • Resource Owner — пользователь, владеющий данными.
  • Client — приложение, которое запрашивает доступ.
  • Authorization Server — сервер, выдающий токены после аутентификации.
  • Resource Server — API, защищающее ресурсы и проверяющее токены.

Популярные потоки (grant types)

  • Authorization Code — для серверных приложений (наиболее безопасный).
  • Client Credentials — для межсерверного взаимодействия (без пользователя).
  • Implicit — устаревший, не рекомендуется.
  • Refresh Token — для получения нового access token без повторного ввода пароля.

JWT (JSON Web Token): структура и принцип работы

Из чего состоит JWT?

JWT — это строка, состоящая из трех частей, разделенных точками:

header.payload.signature
  • Header — тип токена и алгоритм подписи (например, HS256 или RS256).
  • Payload — данные (claims): идентификатор пользователя, роли, срок действия и т.д.
  • Signature — подпись, которая верифицирует, что токен не был изменен.

Преимущества JWT для C#

  • Самодостаточность — все данные о пользователе внутри токена.
  • Легкая проверка на стороне ресурсного сервера без обращения к БД.
  • Поддержка в .NET через библиотеку Microsoft.AspNetCore.Authentication.JwtBearer.

Реализация OAuth 2.0 + JWT на C# в ASP.NET Core

1. Настройка сервера авторизации (выдача JWT)

Создадим минимальный сервер, который принимает логин/пароль и возвращает JWT. Для простоты используем симметричный ключ (HS256).

// Program.cs — сервер авторизации
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "MyAuthServer",
            ValidAudience = "MyApiClient",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SuperSecretKey123!@#$%"))
        };
    });

builder.Services.AddAuthorization();
var app = builder.Build();

app.MapPost("/token", (HttpContext context) =>
{
    // Здесь должна быть проверка логина/пароля из БД
    var claims = new[]
    {
        new Claim(ClaimTypes.Name, "user@example.com"),
        new Claim(ClaimTypes.Role, "User")
    };

    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SuperSecretKey123!@#$%"));
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

    var token = new JwtSecurityToken(
        issuer: "MyAuthServer",
        audience: "MyApiClient",
        claims: claims,
        expires: DateTime.Now.AddMinutes(30),
        signingCredentials: creds);

    return new { token = new JwtSecurityTokenHandler().WriteToken(token) };
});

app.Run();

2. Защита API с помощью JWT (Resource Server)

Теперь создадим защищенный API, который принимает только запросы с валидным JWT.

// Program.cs — защищенный API
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "MyAuthServer",
            ValidAudience = "MyApiClient",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SuperSecretKey123!@#$%"))
        };
    });

builder.Services.AddAuthorization();
builder.Services.AddControllers();

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();

app.MapGet("/api/secure", (HttpContext context) =>
{
    var userName = context.User.Identity?.Name;
    return Results.Ok(new { message = $"Привет, {userName}! Доступ разрешен." });
}).RequireAuthorization();

app.Run();

3. Работа с Refresh Token

Access token обычно живет недолго (15-30 минут). Для продления сессии используется refresh token — долгоживущий токен, который хранится на сервере (например, в БД).

// Пример выдачи refresh token
public class TokenService
{
    private static readonly Dictionary<string, string> _refreshTokens = new(); // В реальности — БД

    public static string GenerateRefreshToken()
    {
        var randomBytes = new byte[32];
        using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
        rng.GetBytes(randomBytes);
        return Convert.ToBase64String(randomBytes);
    }

    public static void SaveRefreshToken(string userId, string refreshToken)
    {
        _refreshTokens[refreshToken] = userId; // Хранить в БД с датой                

Блоги

Рекомендаций по книгам