使用AuthorizationPolicyBuilder时,授权角色无效

问题描述 投票:0回答:2

我已经实现了一个解决方案,允许我阻止同一帐户的多个用户会话。

为此,我在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,如果我删除上面的逻辑所有工作按预期,任何想法?

c# asp.net asp.net-core
2个回答
1
投票

当您调用Authorize时,无论您应用于该方法的角色是什么,都会调用ValidSessionHandler,因为它是您的默认策略。您可以添加一个检查以跳过ValidSessionHanlder中的某些角色。下面的代码将跳过AdminSuperAdmin的会话检查。

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
投票

这是如何配置和适用于基于策略的授权。

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()
{ ... }
© www.soinside.com 2019 - 2024. All rights reserved.