Я хотел бы потребовать одну политику для всех действий на контроллере, и я хотел бы также потребовать вторую политику для всех вызовов «методов редактирования» HTTP (POST, PUT, PATCH и DELETE). То есть методы редактирования должны требовать обеих политик. Из-за требований к реализации, а также из-за желания сохранить код DRY, мне нужно, чтобы последняя политика применялась на уровне контроллера, а не дублировалась во всех методах действий.
В качестве простого примера у меня есть PeopleController
, и у меня также есть два разрешения, реализованные как политики, ViewPeople
и EditPeople
. Прямо сейчас у меня есть:
[Authorize("ViewPeople")]
public class PeopleController : Controller { }
Как мне добавить политику / разрешение EditPeople
, чтобы они «складывались» и применялись только к командам редактирования?
Я столкнулся с двумя проблемами, которые кажутся мне настоящей болью:
- Вы не можете иметь более одного AuthorizeAttribute или более одной политики, указанной в AuthorizeAttribute, AFAIK.
- Вы не можете получить доступ к запросу в настраиваемом AuthorizationHandler, поэтому я не могу проверить HttpMethod, чтобы проверить его.
Я попытался обойти первое с помощью настраиваемого Requirement и AuthorizationHandler, например:
public class ViewEditRolesRequirement : IAuthorizationRequirement
{
public ViewEditRolesRequirement(Roles[] editRoles, Roles[] viewRoles)
=> (EditRoles, ViewRoles) = (editRoles, viewRoles);
public Roles[] EditRoles { get; }
public Roles[] ViewRoles { get; }
}
public class ViewEditRolesHandler : AuthorizationHandler<ViewEditRolesRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ViewEditRolesRequirement requirement)
{
if (context.User != null)
{
var canView = requirement.ViewRoles.Any(r => context.User.IsInRole(r.ToString()));
var canEdit = requirement.EditRoles.Any(r => context.User.IsInRole(r.ToString()));
if (context. // Wait, why can't I get to the bloody HttpRequest??
}
return Task.CompletedTask;
}
}
... но я дошел до if (context.
, прежде чем понял, что у меня нет доступа к объекту запроса.
Единственный ли мой выбор - переопределить метод OnActionExecuting
в контроллере и выполнить там свою авторизацию? Я полагаю, это по крайней мере осуждается?