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.