Hard📖Теория2 min

Microsoft Identity Platform

MSAL, OAuth 2.0 потоки, регистрация приложений, защита API

Microsoft Identity Platform

Microsoft Identity Platform -- экосистема для аутентификации и авторизации приложений через Entra ID. На AZ-204 необходимо знать потоки OAuth 2.0, MSAL и защиту API.

Регистрация приложения

Каждое приложение, использующее Entra ID для аутентификации, должно быть зарегистрировано.

# Регистрация приложения
az ad app create --display-name "OrderManagement API"

# Создание Service Principal
az ad sp create --id <app-id>

При регистрации создаются:

  • Application (client) ID -- уникальный идентификатор приложения
  • Directory (tenant) ID -- идентификатор каталога Entra ID
  • Client Secret или Certificate -- для аутентификации приложения

Потоки OAuth 2.0

Поток Сценарий Участие пользователя
Authorization Code Серверные веб-приложения Да -- пользователь входит через браузер
Authorization Code + PKCE SPA, мобильные приложения Да -- с дополнительной защитой
Client Credentials Сервис-к-сервису (демон, фоновая задача) Нет -- без пользователя
On-Behalf-Of API вызывает другой API от имени пользователя Да -- делегированный доступ

Client Credentials Flow

Используется, когда приложение действует от своего имени (без пользователя). Типичный сценарий: фоновый сервис, Azure Function, daemon.

App -> Entra ID: client_id + client_secret
Entra ID -> App: access_token
App -> API: access_token в заголовке Authorization

Authorization Code Flow

Используется для веб-приложений, где пользователь входит через браузер:

1. App -> Browser: redirect to Entra ID login
2. User -> Entra ID: enters credentials
3. Entra ID -> App: authorization code
4. App -> Entra ID: code + client_secret
5. Entra ID -> App: access_token + refresh_token

MSAL -- Microsoft Authentication Library

MSAL -- официальная библиотека для работы с Microsoft Identity Platform. Она инкапсулирует протоколы OAuth 2.0 и OpenID Connect.

Confidential Client (серверное приложение)

using Microsoft.Identity.Client;

// Создание клиента
var app = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithClientSecret(clientSecret)
    .WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
    .Build();

// Client Credentials Flow (сервис-к-сервису)
var result = await app
    .AcquireTokenForClient(new[] { "https://graph.microsoft.com/.default" })
    .ExecuteAsync();

string accessToken = result.AccessToken;

// Использование токена
httpClient.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", accessToken);

Public Client (SPA, мобильное приложение)

var app = PublicClientApplicationBuilder
    .Create(clientId)
    .WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
    .WithRedirectUri("http://localhost")
    .Build();

var result = await app
    .AcquireTokenInteractive(new[] { "User.Read" })
    .ExecuteAsync();

Кеширование токенов

MSAL автоматически кеширует токены и использует refresh_token для обновления. Для серверных приложений рекомендуется настроить распределенный кеш:

app.AddDistributedTokenCache(services =>
{
    services.AddStackExchangeRedisCache(options =>
    {
        options.Configuration = redisConnectionString;
    });
});

Защита ASP.NET Core API

Настройка аутентификации

// Program.cs
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("OrderAdmin", policy =>
        policy.RequireRole("Admin")
              .RequireClaim("department", "orders"));
});

Конфигурация

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "Audience": "api://your-client-id"
  }
}

Использование в контроллере

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    [HttpGet]
    [Authorize(Policy = "OrderAdmin")]
    public async Task<IActionResult> GetAll()
    {
        // Доступ к claims текущего пользователя
        var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        var roles = User.FindAll(ClaimTypes.Role).Select(c => c.Value);
        // ...
    }
}

Scope vs App Roles

Scope (delegated permissions) -- действия, которые приложение может выполнять от имени пользователя. Пример: User.Read, Mail.Send.

App Roles (application permissions) -- роли, назначаемые приложению или пользователю. Пример: Orders.Admin, Orders.Reader.

Проверь себя

🧪

Какой поток OAuth 2.0 используется для сервис-к-сервису взаимодействия без участия пользователя?

🧪

Для чего используется PKCE в Authorization Code Flow?

🧪

Какой класс MSAL используется для серверных приложений?

🧪

Что такое scope '.default' в Client Credentials Flow?