[英]"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.