Роли авторизации не работают при использовании AuthorizationPolicyBuilder - PullRequest
0 голосов
/ 17 сентября 2018

Я реализовал решение, которое позволяет мне предотвратить несколько сеансов пользователей для одной и той же учетной записи.

Для этого в методе ConfigureServices я добавил следующую конфигурацию:

services.AddIdentity<User, IdentityRole>()
    .AddEntityFrameworkStores<SoccerForecastContext>()
    .AddDefaultTokenProviders();

var defaultPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .AddRequirements(new ValidSessionRequirement())
    .Build();

services.AddAuthorization(options =>
{
    options.DefaultPolicy = defaultPolicy;
});
    services.AddScoped<IUserClaimsPrincipalFactory<User>, ApplicationClaimsPrincipalFactory>();
    services.AddTransient<IAuthorizationHandler, ValidSessionHandler>();

По существу для каждого запроса конвейер будет вызывать

public class ApplicationClaimsPrincipalFactory : UserClaimsPrincipalFactory<User>
{
  private readonly UserManager<User> _userManager;

  public ApplicationClaimsPrincipalFactory(UserManager<User> userManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, optionsAccessor)
  {
      _userManager = userManager;
  }

  public async override Task<ClaimsPrincipal> CreateAsync(User user)
  {
      var claims = await _userManager.GetClaimsAsync(user);
      var session = claims.Where(e => e.Type == "session");
      await _userManager.RemoveClaimsAsync(user, session);
      await _userManager.AddClaimAsync(user, new Claim("session", Guid.NewGuid().ToString()));
      var principal = await base.CreateAsync(user);
      return principal;
  }
}

класс ValidSessionRequirement просто наследует, что:

public class ValidSessionRequirement : IAuthorizationRequirement
{
}

Теперь, если я вызову этот метод:

[HttpGet]
[Authorize(Roles = "Customer, Admin, SuperAdmin")]
public async Task<IActionResult> Profile()
{

Я получаю: AccessDenied, но роль пользователя будет SuperAdmin, если я удаляю логику над всеми работами, как ожидалось, есть идеи?

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

Когда вы вызываете Authorize, вызывается ваш ValidSessionHandler независимо от того, какие роли вы применяете к методу, потому что это ваша политика по умолчанию. Вы можете добавить проверку, чтобы пропустить определенные роли в вашем ValidSessionHanlder. Приведенный ниже код пропустит проверку сеанса для Admin и SuperAdmin.

public class ValidSessionHandler : AuthorizationHandler<ValidSessionRequirement>
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly SignInManager<IdentityUser> _signInManager;

    public ValidSessionHandler(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
    {
        _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
        _signInManager = signInManager ?? throw new ArgumentNullException(nameof(signInManager));
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidSessionRequirement requirement)
    {
        // if the user isn't authenticated then no need to check session
        if (!context.User.Identity.IsAuthenticated)
            return;

        // get the user and session claim
        var user = await _userManager.GetUserAsync(context.User);

        var claims = await _userManager.GetClaimsAsync(user);

        // get roles and skip check if Admin or SuperAdmin
        var roles = await _userManager.GetRolesAsync(user);

        foreach(var role in roles)
        {
            if(role == "Admin" || role == "SuperAdmin")
            {
                context.Succeed(requirement);
                return;
            }
        }

        var serverSession = claims.First(e => e.Type == "session");

        var clientSession = context.User.FindFirst("session");

        // if the client session matches the server session then the user is authorized
        if (serverSession?.Value == clientSession?.Value)
        {
            context.Succeed(requirement);
        }

        return;
    }
}
0 голосов
/ 17 сентября 2018

Это то, как настроить и что работает для авторизации на основе политик.

В Startup политики настройки класса

public void ConfigureServices(IServiceCollection services)
{
    // ... 
    // Configure security policies 
    services.AddAuthorization(options =>
    {
        options.AddPolicy("SuperAdmins", policy => policy.RequireRole("SuperAdmin"));
        options.AddPolicy("Admins", policy => policy.RequireRole("Admin", "SuperAdmin"));
        options.AddPolicy("Customers", policy => policy.RequireRole("Customer", "Admin", "SuperAdmin"));
    });
    // ... 
    services.AddScoped<IUserClaimsPrincipalFactory<User>, MyUserClaimsFactory>();
    // ... 
}

В вашем UserClaimsPrincipalFactory вы можете добавить пользовательские претензии, например:

protected override async Task<ClaimsIdentity> GenerateClaimsAsync(User user)
{
    var userId = user.Id;
    user = await UserManager.Users.SingleAsync(u => u.Id == userId);

    // Add role claims
    var identity = await base.GenerateClaimsAsync(user);

    // Add custom claims for application user properties we want to store in claims (in cookies) which allows to get common values on UI without DB hit)
    identity.AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName ?? ""));
    identity.AddClaim(new Claim(ClaimTypes.Surname, user.LastName ?? ""));

    // Add your session or any other claims here if needed

    return identity;
}

В вашем атрибуте авторизации контроллера следует использовать Policy имя и выглядеть следующим образом:

[Authorize(Policy = "SuperAdmins")]
public async Task<IActionResult> Profile()
{ ... }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...