Как добавить авторизацию в приложение на C#?

«Как добавить авторизацию в приложение на C#?» — вопрос из категории Безопасность, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Добавление авторизации зависит от типа приложения (Web API, MVC, Blazor, Desktop). Общий принцип — аутентификация (кто вы?) и авторизация (что вам можно?).

1. Для веб-приложений (ASP.NET Core) — использование встроенной инфраструктуры:

Аутентификация с JWT для API:

// Startup.cs / Program.cs
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = "your-issuer",
            ValidateAudience = true,
            ValidAudience = "your-audience",
            ValidateLifetime = true,
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(configuration["Jwt:SecretKey"]))
        };
    });

services.AddAuthorization(); // Добавляет сервисы авторизации

app.UseAuthentication(); // Middleware для проверки токена
app.UseAuthorization();

Защита endpoint с помощью политик (Policy-Based Authorization):

// Определение политики (например, требующей роль "Admin")
services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy =>
        policy.RequireRole("Admin"));
    // Более сложная политика с кастомным требованием
    options.AddPolicy("MinimumAge", policy =>
        policy.Requirements.Add(new MinimumAgeRequirement(18)));
});

// Применение на контроллере или action
[ApiController]
[Route("api/[controller]")]
[Authorize] // Требует аутентификации для всех действий
public class AdminController : ControllerBase
{
    [HttpGet("reports")]
    [Authorize(Policy = "AdminOnly")] // Требует роль Admin
    public IActionResult GetReports() => Ok("Secret report data");
}

2. Для десктопных приложений (WPF/WinForms): Чаще используется кастомная логика или интеграция с Active Directory / Identity Server.

// Пример простой проверки после ввода логина/пароля
public bool AuthenticateUser(string username, string password)
{
    // 1. Найти хеш пароля пользователя в БД
    var user = dbContext.Users.FirstOrDefault(u => u.Username == username);
    if (user == null) return false;

    // 2. Верифицировать хеш с использованием надежного алгоритма
    // НИКОГДА не храните пароли в открытом виде!
    return BCrypt.Net.BCrypt.Verify(password, user.PasswordHash);
}

// 3. После успешной аутентификации создать контекст пользователя (принципала)
var identity = new GenericIdentity(username);
identity.AddClaim(new Claim(ClaimTypes.Role, user.Role));
var principal = new GenericPrincipal(identity, new[] { user.Role });
Thread.CurrentPrincipal = principal; // Установка для текущего потока

Best Practices и ключевые решения:

  • Хранение секретов: Ключи JWT, строки подключения храните в менеджере секретов (Azure Key Vault, HashiCorp Vault) или UserSecrets для разработки.
  • HTTPS: Всегда используйте HTTPS в продакшене для защиты токенов и данных аутентификации.
  • Время жизни токенов: Устанавливайте короткое время жизни Access Token и используйте Refresh Token для его обновления.
  • Готовые решения: Для сложных сценариев рассмотрите IdentityServer4/Duende IdentityServer как полноценный сервис идентификации с поддержкой OAuth 2.0 и OpenID Connect.