Я задавал подобный вопрос раньше, и с помощью других я добился определенного прогресса, но все еще не уверен, что я сделал неправильно или пропустил здесь.
Мое приложение довольно простое: пользователи домена проходят проверку подлинности.Аутентифицированный пользователь (автор) создает запрос, сохраняет в базе данных.Другие аутентифицированные пользователи могут только просматривать запрос.Авторы и администраторы могут редактировать / удалять запрос.
Это один из примеров, которым я следовал: Различные функции API для разных ролей
А другой PoliciesAuthApp:https://github.com/aspnet/Docs/tree/master/aspnetcore/security/authorization/policies/samples/PoliciesAuthApp1 Я не уверен, как PermissionHandler используется / регистрируется / вызывается здесь.
Вот мой код:
Startup.cs
// Add Authentication
// Global filter
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireRole("Role - Domain Users")
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
// Add Authorization Handlers
services.AddAuthorization(options =>
{
options.AddPolicy("EditPolicy", policy => policy.Requirements.Add(new EditRequirement()));
});
services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
EditRequirement.cs
public class EditRequirement : IAuthorizationRequirement
{
}
PermissionHandler.cs
public class PermissionHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is ReadRequirement)
{
if (IsOwner(context.User, context.Resource) ||
IsAdmin(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
else if (requirement is EditRequirement ||
requirement is DeleteRequirement)
{
if (IsOwner(context.User, context.Resource) || IsAdmin(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
}
return Task.CompletedTask;
}
private bool IsAdmin(ClaimsPrincipal user, object resource)
{
if (user.IsInRole("Role - Administrator"))
{
return true;
}
return false;
}
private bool IsOwner(ClaimsPrincipal user, object resource)
{
if (resource is CreateRequestViewModel)
{
var ctx = (CreateRequestViewModel)resource;
if (ctx.RequestEnteredBy.Equals(user.Identity.Name))
{
return true;
}
}
else if (resource is AuthorizationFilterContext)
{
var afc = (AuthorizationFilterContext)resource;
// This is not right, but I don't know how to deal with AuthorizationFilterContext
// type passed into resource parameter when I click Edit button trying to edit the request
if (afc.HttpContext.User.Identity.Name.Equals(user.Identity.Name))
{
return true;
}
}
else if (resource is Request)
{
var r = (Request)resource;
if (r.RequestEnteredBy.Equals(user.Identity.Name))
{
return true;
}
}
return false;
}
private bool IsSponsor(ClaimsPrincipal user, object resource)
{
// Code omitted for brevity
return true;
}
}
RequestsController.cs
private IAuthorizationService _authorizationService;
public RequestsController(ApplicationModelContext context, IAuthorizationService authorizationService)
{
_context = context;
_authorizationService = authorizationService;
}
[Authorize(Policy = "EditPolicy")]
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
CreateRequestViewModel crvm = new CreateRequestViewModel();
var request = await _context.Request
.SingleOrDefaultAsync(m => m.RequestId == id);
if (request == null)
{
return NotFound();
}
var authorizationResult = await _authorizationService.AuthorizeAsync(User, request, "EditPolicy");
if (authorizationResult.Succeeded)
{
// Load request contents and return to the view
return View(crvm);
}
// This needs to be changed to redirect to a message screen saying no permission
return RedirectToAction("Details", new { id = request.RequestId });
}
Когда я отлаживал приложение, я обнаружил, что:
- При первой загрузке страницы запросов из базы данных она передает объект типа CreateRequestViewModel впараметр ресурса метода IsOwner в PermissionHandler.
- После нажатия кнопки «Изменить» элемента запроса на странице он передает тип AuthorizationFilterContext
- Затем переходит в действие «Редактировать» в ReuqestController, который отправляет тип запроса (в _authorizationService.AuthorizeAsync).
Не уверен, что я сделал что-то дублированное или полностью смешанное с разными подходами.
Любой совет будет очень признателен.