MVC Core Authorization
Я использую MVC Core для веб-сайта, где у меня есть следующая проблема, чтобы разобраться.
Допустим, у меня есть две группы GroupA и GroupB, и у этих групп есть несколько сущностей. Субъект либо принадлежит Группе A или Группе B, но не одновременно обоим. Чтобы защитить обновление этих объектов, я определил следующую политику:
AuthorizationOptions.AddPolicy("UpdateEntityInGroupAPolicy", policy =>
{
policy.RequireClaim("ClaimThatAllowsUpdatingEntityInGroupA");
});
Эта политика гарантирует, что пользователи, которые хотят обновить сущность в GroupA, имеют претензию ClaimThatAllowsUpdatingEntityInGroupA. Аналогичная политика может быть создана для GroupB с заявкой ClaimThatAllowsUpdatingEntityInGroupB.
Более того, давайте предположим, что GroupA имеет сущность с идентификатором 5, а GroupB имеет сущность с идентификатором 10. Если данный пользователь (у которого есть утверждение ClaimThatAllowsUpdatingEntityInGroupA, но не утверждение ClaimThatAllowsUpdatingEntityInGroupB) обновляет сущность с идентификатором 5 по адресу url:
http://example.com/entity/5/update
Как мне теперь убедиться, что пользователь не просто меняет 5 в URL-адресе на 10, а фактически обновляет другой объект с идентификатором 10 в GroupB?
Я надеюсь, что я ясен с вопросом и спасибо за любую помощь:)
1 ответ
Если вы хотите использовать Authorize
атрибут, вы не можете сделать это, потому что фильтр авторизации не знает о вашей сущности. Таким образом, для вашего случая авторизация на основе ресурсов кажется правильным решением.
Сначала предположим, что ваша сущность похожа на:
public class YourEntity
{
public int Id { get; set; }
public string Group { get; set; }
//...
}
Для реализации авторизации на основе ресурсов
Создайте требование:
public class UpdateRequirement : IAuthorizationRequirement
{
}
Создать обработчик авторизации для требования и объекта
public class YourEntityAuthorizationHandler : AuthorizationHandler<UpdateRequirement, YourEntity>
{
public override Task HandleRequirementAsync(AuthorizationHandlerContext context,
UpdateRequirement requirement,
YourEntity resource)
{
if(resource.Group == "GroupA" &&
context.User.HasClaim("ClaimThatAllowsUpdatingEntityInGroupA"))
{
context.Succeed(requirement);
}
else if(resource.Group == "GroupB" &&
context.User.HasClaim("ClaimThatAllowsUpdatingEntityInGroupB"))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
Наконец, используйте его в логике вашего контроллера:
public async Task<IActionResult> Update([FromServices]IAuthorizationService authorizationService, int id)
{
var entity= _entityRepository.Get(id);
if (entity == null)
{
return new NotFoundResult();
}
if (await _authorizationService.AuthorizeAsync(User, entity, new UpdateRequirement()))
{
return View(entity);
}
else
{
return new ChallengeResult();
}
}
Также смотрите пример @blowdart