Как добавить авторизацию в приложение на 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.

Ответ 18+ 🔞

Ну что, дружище, давай разберём эту пиздатую тему про авторизацию, а то без неё твоё приложение — как хата без замка, любой левый мудак зайдёт и насрет посреди ковра.

Смотри, тут всё зависит от того, какую хуйню ты пишешь. Веб-апишка, сайт на MVC, эта ваша модная Blazor-залупа или классический десктоп. Но суть одна: сначала мы выясняем, кто ты такой (аутентификация), а потом решаем, куда тебе можно совать свой любопытный нос (авторизация).

1. Для веб-приложений на ASP.NET Core (самый частый случай)

Тут всё уже почти готово, надо только правильно подкрутить.

Если делаешь API и хочешь JWT-токены (это такие цифровые пропуски):

// 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();

А теперь самое вкусное — политики доступа. Это когда ты не просто говоришь "зайди, если ты свой", а "зайди, только если ты из бухгалтерии и старше 18".

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

// И навешиваем эту защиту на контроллеры или методы
[ApiController]
[Route("api/[controller]")]
[Authorize] // Сюда просто так не зайти, надо представиться
public class AdminController : ControllerBase
{
    [HttpGet("reports")]
    [Authorize(Policy = "AdminOnly")] // А сюда — только если ты босс
    public IActionResult GetReports() => Ok("Secret report data");
}

2. Для десктопных приложений (WPF, WinForms)

Тут обычно своя атмосфера, часто кастомная логика или интеграция с каким-нибудь корпоративным адом вроде Active Directory.

// Допустим, у тебя есть форма ввода логина и пароля
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; // И вешаем это всё на текущий поток

Важные моменты, чтобы не обосраться:

  • Секреты: Ключи от JWT, строки подключения к базе — это не для appsettings.json в продакшене. Прячь их в Azure Key Vault, HashiCorp Vault или хотя бы в UserSecrets на время разработки.
  • HTTPS: В продакшене — всегда. Иначе твои токены будут летать по сети как голые бабы по пляжу, все увидят.
  • Время жизни токена: Делай Access Token'ы короткоживущими (минуты/часы), а для обновления используй Refresh Token. Так безопаснее, ёпта.
  • Не изобретай велосипед: Если сценарий сложный (много приложений, единый вход, сторонние логины) — бери готовое решение вроде IdentityServer4 (или Duende IdentityServer). Они уже всё за тебя продумали, поддержка OAuth 2.0 и OpenID Connect из коробки.

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