“context.Resource as AuthorizationFilterContext” returning null in ASP.NET Core 3.0

前端 未结 6 534
情书的邮戳
情书的邮戳 2020-12-16 07:50

I am trying to implement a custom authorization requirement following a tutorial. It seems like context.Resource no longer contains AuthorizationFilterCo

6条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-16 08:28

    public class CanEditOnlyOtherAdminRolesAndClaimsHandler :
       AuthorizationHandler
        {
           private readonly IHttpContextAccessor httpContextAccessor;
    
           public CanEditOnlyOtherAdminRolesAndClaimsHandler(IHttpContextAccessor httpContextAccessor)
           {
                this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
           }
    
           protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
           ManageAdminRolesAndClaimsRequirement requirement)
            {
                if (context.User == null || !context.User.Identity.IsAuthenticated)
                {
                    context.Fail();
                    return Task.CompletedTask;
                }
    
                string loggedInAdminId =
                    context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;
    
                string adminIdBeingEdited = httpContextAccessor.HttpContext.Request.Query["userId"].ToString();
    
                if (context.User.IsInRole("Admin") &&
                context.User.HasClaim(claim => claim.Type == "Edit Role" && claim.Value == "true") &&
                adminIdBeingEdited.ToLower() != loggedInUserId.ToLower())
                {
                    context.Succeed(requirement);
                }
    
                return Task.CompletedTask;
            }
        }
    }
    

    Then add the following services to ConfigureServices method in Startup class:

     public void ConfigureServices(IServiceCollection services)
            {           
              services.AddAuthorization(options =>
                {
                 options.AddPolicy("ManageRolesPolicy", policy => policy.Requirements.Add(new ManageAdminRolesAndClaimsRequirement()));
                }
    
              services.AddScoped();       
          }
    

    If you want to handle a multiple custom authorization for a requirement:

    in CanEditOnlyOtherAdminRolesAndClaimsHandler class you check if the user is in Admin role and has Edit Role claim. Let's suppose that you require that the user must to be in Super Admin role, in this scenario, you can either:

    - edit the condition in CanEditOnlyOtherAdminRolesAndClaimsHandler class to be as a following:

    if (context.User.IsInRole("Admin") &&
                    context.User.HasClaim(claim => claim.Type == "Edit Role" && claim.Value == "true") &&
                    adminIdBeingEdited.ToLower() != loggedInUserId.ToLower() || 
                    context.User.IsInRole("Super Admin") && adminIdBeingEdited.ToLower() != loggedInUserId.ToLower())
                    {
                        context.Succeed(requirement);
                    }
    

    - or customize another authorization handler for the new requirement which in this case is Super Admin role:

    Create a new class and name it ManageRolesAndClaimsSuperAdminHandler, the implementation of this class should be as follows

    public class ManageRolesAndClaimsSuperAdminHandler : AuthorizationHandler
        {
            private readonly IHttpContextAccessor httpContextAccessor;
    
            public ManageUsersRolesSuperAdminHandler(IHttpContextAccessor httpContextAccessor)
            {
                this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
            }
    
            protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ManageAdminRolesAndClaimsRequirement  requirement)
            {
            if (context.User == null || !context.User.Identity.IsAuthenticated)
                {
                    context.Fail();
                    return Task.CompletedTask;
                }
    
                string loggedInAdminId = context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;
    
                string adminIdBeingEdited = httpContextAccessor.HttpContext.Request.Query["userId"].ToString();
    
                if (context.User.IsInRole("Super Admin") && adminIdBeingEdited.ToLower() != loggedInUserId.ToLower())
                {
                    context.Succeed(requirement);
                }
                return Task.CompletedTask;
            }
        }
    

    Now register the new handler in ConfigureServices method in Startup class

    public void ConfigureServices(IServiceCollection services)
          {        
              services.AddAuthorization(options =>
                {
                 options.AddPolicy("ManageRolesPolicy", policy => policy.Requirements.Add(new ManageAdminRolesAndClaimsRequirement()));
                }
    
              services.AddScoped();
              services.AddScoped();
          }
    

提交回复
热议问题