我正在尝试按照教程实施自定义授权要求。这好像是
context.Resource
不再包含AuthorizationFilterContext
,结果:
var authFilterContext = context.Resource as AuthorizationFilterContext;
返回null
,其余逻辑失败。我也无法获取查询字符串值,因为它为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中解决此问题?
答案 0 :(得分:4)
这是由于.NET Core 3.0中新的端点路由所致。
引用以下票证。
这是因为在ASP.NET Core 3.0中使用终结点路由时:
Mvc将不再将AuthorizeFilter添加到ActionDescriptor,并且 ResourceInvoker将不会调用AuthorizeAsync() https://github.com/aspnet/AspNetCore/blob/90ab2cb965aeb8ada13bc4b936b3735ca8dd28df/src/Mvc/Mvc.Core/src/ApplicationModels/AuthorizationApplicationModelProvider.cs#L40
Mvc会将所有筛选器作为元数据添加到端点。 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/AuthorizationMiddleware.cs#L63
新方法。
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();
}
}
答案 1 :(得分:2)
公共类CanEditOnlyOtherAdminRolesAndClaimsHandler:AuthorizationHandler { 私有只读IHttpContextAccessor httpContextAccessor; 公共CanEditOnlyOtherAdminRolesAndClaimsHandler(IHttpContextAccessor httpContextAccessor) { this.httpContextAccessor = httpContextAccessor ??抛出新的ArgumentNullException(nameof(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(claim =>
claim.Type == "Edit Role" && claim.Value == "true") && adminIdBeingEdited.ToLower() != loggedInAdminId.ToLower())
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
答案 2 :(得分:0)
private readonly IHttpContextAccessor httpContextAccessor;
public CanEditOnlyOtherAdminRolesAndClaimsHandler(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
答案 3 :(得分:0)
在[Authorize]属性的上下文中,Resource属性仅是AuthorizationFilterContext。
答案 4 :(得分:0)
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;
}
}
}
然后将以下服务添加到ConfigureServices
类的Startup
方法中:
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;
}
}
现在在ConfigureServices
类的Startup
方法中注册新的处理程序
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>();
}
答案 5 :(得分:0)
如果在控制器中使用Rout属性,则startup.cs中的更改 您可以替换
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "home",
pattern: "{controller=Home}");
});
在Configure()中与此
app.UseMvc(routes =>
{
routes.MapRoute(
name: "home",
template: "{controller=Home}");
});
并在ConfigureSevices()中禁用端点路由
services.AddMvc().AddMvcOptions(mvcopt=> { mvcopt.EnableEndpointRouting = false;});
在Asp .Net Core 5中也可以使用