Nano Hash - криптовалюты, майнинг, программирование

Авторизация .Net Core с индивидуальным требованием / обработчиком

Я задавал аналогичный вопрос раньше, и с помощью других я добился некоторого прогресса, но до сих пор не уверен, что я сделал не так или пропустил здесь.

Мое приложение довольно простое: пользователи домена проходят аутентификацию. Прошедший проверку пользователь (автор) создает запрос, сохраняет его в базе данных. Другие аутентифицированные пользователи могут только просматривать запрос. Пользователи-авторы и администраторы могут редактировать / удалять запрос.

Это один из примеров, которым я следовал: Различные функции 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.
  • После нажатия кнопки Edit элемента запроса на странице он передает тип AuthorizationFilterContext
  • Затем переходит в действие Edit в ReuqestController, которое отправляет тип запроса (в _authorizationService.AuthorizeAsync).

Не уверен, что я сделал что-то дублированное или полностью смешанное с разными подходами.

Любой совет будет очень признателен.


  • @TaoZhou Я не уверен, что я что-то пропустил или мой подход неправильный. Один из примеров, которым я следовал, - github.com. / aspnet / Docs / blob / master / aspnetcore / security /, и я не уверен, как используется PermissionHandler, он нигде не зарегистрирован и не вызывается. 21.02.2019

Ответы:


1

Похоже, вы смешиваете политику и авторизацию на основе ресурсов. На основе ресурсов звучит так, как вы хотите, поскольку вы, возможно, не захотите создавать политики для каждой операции CRUD, то есть «CreateUserPolicy», «UpdateUserPolicy», а затем передавать различные требования для каждой из них. См. Это руководство для авторизации на основе ресурсов: https://docs.microsoft.com/en-us/aspnet/core/security/authorization/resourcebased?view=aspnetcore-2.2

Для авторизации в отношении пользовательского ресурса я создал UserAuthorizationHandler:

Startup.cs:

services.AddScoped<IAuthorizationHandler, UserAuthorizationHandler>();

UserAuthorizationHandler.cs

public class UserAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, User>
{
    private readonly IPermissionRepository _permissionRepository;

    public UserAuthorizationHandler(IPermissionRepository permissionRepository)
    {
        _permissionRepository = permissionRepository;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement, User resource)
    {
        var authUserId = int.Parse(context.User.FindFirstValue(ClaimTypes.NameIdentifier));

        if (requirement == AuthorizationOperations.Create)
        {
            if (await CanCreate(authUserId))
            {
                context.Succeed(requirement);
            }
        }
        else if (requirement == AuthorizationOperations.Read)
        {
            if (await CanRead(authUserId, resource))
            {
                context.Succeed(requirement);
            }
        }
    }

    /// <summary>
    /// User can create if they have 'create' 'users' permission.
    /// </summary>
    /// <param name="authUserId">The requesting user</param>
    /// <returns></returns>
    public async Task<bool> CanCreate(int authUserId)
    {
        return await _permissionRepository.UserHasPermission(authUserId, "create", "users");
    }

    /// <summary>
    /// User can read if reading themselves or they have the 'read' 'users' permission.
    /// </summary>
    /// <param name="authUserId">The requesting user</param>
    /// <param name="user">The requested resource</param>
    /// <returns></returns>
    public async Task<bool> CanRead(int authUserId, User user)
    {
        return authUserId == user.Id || await _permissionRepository.UserHasPermission(authUserId, "read", "users");
    }
}

Контроллер:

  var authorized = await _authorizationService.AuthorizeAsync(User, new User { Id = id}, AuthorizationOperations.Read);
  if (!authorized.Succeeded)
  {
    return Unauthorized();
  }
11.09.2019
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..