簡體   English   中英

“context.Resource as AuthorizationFilterContext”在 ASP.NET Core 3.0 中返回 null

[英]"context.Resource as AuthorizationFilterContext" returning null in ASP.NET Core 3.0

我正在嘗試按照教程實現自定義授權要求。 似乎context.Resource不再包含AuthorizationFilterContext ,因此:

var authFilterContext = context.Resource as AuthorizationFilterContext;

返回null ,其余邏輯失敗。 我也無法獲取查詢字符串值,因為它為空。 以下是代碼:

public class CanEditOnlyOtherAdminRolesAndClaimsHandler :
   AuthorizationHandler<ManageAdminRolesAndClaimsRequirement>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
       ManageAdminRolesAndClaimsRequirement requirement)
        {
            var authFilterContext = context.Resource as AuthorizationFilterContext;
            if (authFilterContext == null)
            {
                return Task.CompletedTask;
            }

            string loggedInAdminId =
                context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;

            string adminIdBeingEdited = authFilterContext.HttpContext.Request.Query["userId"];

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

            return Task.CompletedTask;
        }
    }
}

我應該如何在 ASP.NET Core 3.0 中解決這個問題?

這是由於 .NET Core 3.0 中的新端點路由。

引用下面的票。

這是因為在 ASP.NET Core 3.0 中使用端點路由時:

Mvc 將不再向 ActionDescriptor 添加 AuthorizeFilter 並且 ResourceInvoker 將不會調用 AuthorizeAsync() https://github.com/aspnet/AspNetCore/blob/90ab2cb965aeb8ada13bc4b936b3735ca8dd28df/src/Mvc/Mvc.Core/src/ApplicationModels4Providers/Authorc

Mvc 會將所有過濾器作為元數據添加到 endpoint.Metadata https://github.com/aspnet/AspNetCore/blob/5561338cfecac5ca4b1dda2f09a7f66153d0b5fe/src/Mvc/Mvc.Core/src/Routing/ActionEndpointFactory.cs#L348

而是由 AuthorizationMiddleware 調用 AuthorizeAsync() 並且資源是端點https://github.com/aspnet/AspNetCore/blob/5561338cfecac5ca4b1dda2f09a7f66153d0b5fe/src/Security/Authorization/Policy/src/AuthorizationMiddlesc。

新方法。

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CookieOrTokenAuthorizationRequirement requirement)
{
    if (context.Resource is Endpoint endpoint)
    {
        if (endpoint.Metadata.OfType<IFilterMetadata>().Any(filter => filter is MyFilter))
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }
    }
}

https://github.com/dotnet/aspnetcore/issues/11075

還值得注意的是,使用新上下文您將無法像以前使用 AuthorizationFilterContext 一樣訪問路由數據。 您需要將 IHttpContextAccessor 注入 AuthorizationHandler。

// Ensure your handler is registered as scoped
services.AddScoped<IAuthorizationHandler, InvestorRequirementHandler>();


public class InvestorRequirementHandler : AuthorizationHandler<InvestorRequirement>
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public InvestorRequirementHandler(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, InvestorRequirement requirement)
    {
        var tenant = httpContextAccessor.HttpContext.GetRouteData().Values[ExceptionHandlerMiddleware.TenantCodeKey].ToString();
    }
}
public class CanEditOnlyOtherAdminRolesAndClaimsHandler :
            AuthorizationHandler<ManageAdminRolesAndClaimsRequirement>
{
    private readonly IHttpContextAccessor httpContextAccessor;
    public CanEditOnlyOtherAdminRolesAndClaimsHandler(
            IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;    
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
            ManageAdminRolesAndClaimsRequirement requirement)
    {

        var loggedInAdminId = context.User.Claims
            .FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value.ToString();

        var adminIdBeingEdited = httpContextAccessor.HttpContext
            .Request.Query["userId"].ToString();

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

        return Task.CompletedTask;
    }

}
public class CanEditOnlyOtherAdminRolesAndClaimsHandler :
   AuthorizationHandler<ManageAdminRolesAndClaimsRequirement>
    {
       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;
        }
    }
}

然后將以下服務添加到Startup類的ConfigureServices方法中:

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

          services.AddScoped<IAuthorizationHandler, CanEditOnlyOtherAdminRolesAndClaimsHandler>();       
      }

如果要處理一個需求的多個自定義授權:

CanEditOnlyOtherAdminRolesAndClaimsHandler類中,您檢查用戶是否處於Admin角色並具有Edit Role聲明。 假設您要求用戶必須是Super Admin角色,在這種情況下,您可以:

- 編輯CanEditOnlyOtherAdminRolesAndClaimsHandler類中的條件如下:

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);
                }

- 或為新要求定制另一個授權處理程序,在這種情況下是Super Admin角色:

新建一個類,命名為ManageRolesAndClaimsSuperAdminHandler ,這個類的實現應該如下

public class ManageRolesAndClaimsSuperAdminHandler : AuthorizationHandler<ManageAdminRolesAndClaimsRequirement>
    {
        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;
        }
    }

現在在Startup類的ConfigureServices方法中注冊新的處理程序

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

          services.AddScoped<IAuthorizationHandler, CanEditOnlyOtherAdminRolesAndClaimsHandler>();
          services.AddScoped<IAuthorizationHandler, ManageRolesAndClaimsSuperAdminHandler>();
      }
    private readonly IHttpContextAccessor httpContextAccessor;
    public CanEditOnlyOtherAdminRolesAndClaimsHandler(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));

    }

Resource 屬性將僅是 [Authorize] 屬性上下文中的 AuthorizationFilterContext。

如果您在控制器中使用 Rout 屬性,則在 startup.cs 中的更改您可以替換它

  app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
               name: "home",
               pattern: "{controller=Home}");
        });

在 Configure() 中使用這個

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "home",
                template: "{controller=Home}");
        });

並在 ConfigureServices() 中禁用端點路由

   services.AddMvc().AddMvcOptions(mvcopt=> { mvcopt.EnableEndpointRouting = false;});

也適用於 Asp .Net Core 5

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM