Политики, роли, claims-based и resource-based авторизация

↑ 3.4 Аутентификация и авторизация · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Проверяется умение выбрать модель доступа: роли, claims, политики или проверка по ресурсу.

Объяснение

МодельПримерКогда
Role-based[Authorize(Roles = "Admin")]простые системы
Claims-basedRequireClaim("department", "sales")атрибуты пользователя
Policy-basedRequireAssertion, свои requirementsсложные правила
Resource-based«может ли user изменить этот документ»владение, ACL
builder.Services.AddAuthorizationBuilder()
    .AddPolicy("Adult", p => p.RequireClaim("age").RequireAssertion(c => int.Parse(c.User.FindFirstValue("age")!) >= 18))
    .AddPolicy("CanEditOrders", p => p.Requirements.Add(new EditOrdersRequirement()));
 
app.MapDelete("/orders/{id}", Delete).RequireAuthorization("CanEditOrders");

Resource-based

public class OrderOwnerHandler : AuthorizationHandler<OwnerRequirement, Order>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext ctx, OwnerRequirement req, Order order)
    {
        if (order.OwnerId == ctx.User.FindFirstValue(ClaimTypes.NameIdentifier)) ctx.Succeed(req);
        return Task.CompletedTask;
    }
}
 
var result = await authz.AuthorizeAsync(User, order, new OwnerRequirement());
if (!result.Succeeded) return Forbid();

Ресурс нужно сначала загрузить, поэтому проверка выполняется в коде, а не атрибутом.

Нюансы и подводные камни

  • IDOR: проверяйте доступ к объекту, а не только роль (/orders/123 чужого пользователя).
  • Множество requirement-ов в одной политике — AND; несколько handlers одного requirement — OR.
  • Фильтруйте выборки по владельцу на уровне запроса (Where(o => o.OwnerId == userId)).
  • Проверки прав только на UI не защищают API.

Практика

  1. Реализуйте политику «владелец или админ».
  2. Добавьте resource-based handler для заказов и тест на попытку доступа к чужому.
  3. Настройте fallback policy для всего API.

Вопросы с ответами

Связанные темы