使用AuthorizationPolicyBuilder时授权角色不起作用

时间:2018-09-17 07:15:59

标签: c# asp.net asp.net-core

我已经实施了一个解决方案,该解决方案使我可以防止同一帐户出现多个用户会话。

为此,我在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 :(得分: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;
    }
}

答案 1 :(得分:0)

这是配置方法,适用于基于策略的授权。

void outchar(int c)类中配置策略

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