如何在ASP.NET Core 5.0中获取我的授权策略要求中的用户输入参数



我想授权用户只查看他们自己的资源(例如:Audits实体(。所以在AuditController中,我有:

[MyAuthorize(Policy = nameof(ValidUserToSeeAuditAuthorizationHandler))]
[HttpGet]
public async Task<JsonResult<AuditView>> GetByIdAsync(Guid id)
{
// my business to fetch the audit info based by its id
// ...      
return result;
}

然后我创建了我的RequirementAuthorizationHandler类:

public class ValidUserToSeeAuditRequirment : IAuthorizationRequirement
{
public ValidUserToSeeAuditRequirment(Guid auditId)
{
auditId = auditId;
}

public Guid AuditId { get; }
}
public class ValidUserToSeeAuditAuthorizationHandler : AuthorizationHandler<ValidUserToSeeAuditRequirment>
{
private readonly AppUserManager _userManager;
private readonly IUnitOfWork _appDbContext;
public ValidUserToSeeAuditAuthorizationHandler(AppUserManager userManager, IUnitOfWork appDbContext)
{
_userManager = userManager;
_appDbContext = appDbContext;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidUserToSeeAuditRequirment requirement)
{
if (!context.User.IsAuthenticated())
{
context.Fail();
return Task.CompletedTask;
}
var theAudit = _appDbContext.Set<Audit>().SingleOrDefault(x => x.Id == requirement.AuditId);
var authenticatedUserId = Convert.ToInt32(context.User.GetSubjectId());

// If the authenticated user created the audit, then he/she is valid to see it
if (theAudit.SubjectauthenticatedUserId == authenticatedUserId)
{
// valid
context.Succeed(requirement);
return Task.CompletedTask;
}
// he/she is not authorized to see the resource (audit)
context.Fail();
return Task.CompletedTask;
}
}

但是在Startup类中,我想要配置授权策略。如何配置Requirement类以从控制器的操作方法获取用户输入参数?

services.AddAuthorization(options =>
{
// another policies
// ...

options.AddPolicy(name: nameof(ValidUserToSeeAuditAuthorizationHandler),
policy =>
{
policy.RequireAuthenticatedUser();
policy.AddRequirements(new ValidUserToSeeAuditRequirment( /****** HERE, how to pass the controller action method parameters ******/));
});
});
services.AddTransient<IAuthorizationHandler, ValidUserToSeeAuditAuthorizationHandler>();

您可以自定义AuthorizationPolicy提供程序来获取参数。

public class CustomAuthorizepolicyProvider: DefaultAuthorizationPolicyProvider
{
public CustomAuthorizepolicyProvider(IOptions<AuthorizationOptions> options):base(options)
{
}
public override Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{

if (policyName=="[specified plicyname]")
{
var authorizePolicy = new AuthorizationPolicyBuilder();
authorizePolicy.AddRequirements(new ValidUserToSeeAuditRequirment(/* give the parameter*/)).Build();
return Task.FromResult(authorizePolicy);
}
return base.GetPolicyAsync(policyName);
}
}

注入启动。注意:它是一个单例。

services.AddSingleton<IAuthorizationPolicyProvider,CustomAuthorizepolicyProvider>();

我最终得到了这个解决方案:

/// <summary>
/// 
/// </summary>
public class ValidUserToSeeAuditRequirment : IAuthorizationRequirement
{

}
/// <summary>
/// Only an Admin and the authorized user can see the Audit
/// </summary>
public class ValidUserToSeeAuditAuthorizationHandler : AuthorizationHandler<ValidUserToSeeAuditRequirment>
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ValidUserToSeeAuditAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidUserToSeeAuditRequirment requirement)
{
// If he has the Admin Role, then he can see the Audit
if (context.User.HasClaim(x => x.Type.ToUpperInvariant() == "ROLE" && x.Value.ToUpperInvariant() == "ADMIN"))
{
context.Succeed(requirement);
return;
}
// Get the audit id from the Routing
var auditIdFromRoute = _httpContextAccessor.HttpContext.GetRouteData()?.Values["id"].ToString();
if (auditIdFromRoute is null || !Guid.TryParse(auditIdFromRoute, out Guid requestingAuditId))
{
context.Fail();
return;
}
// get the authenticated user
var userId = Convert.ToInt32(context.User.GetSubjectId());

// check if the user has authorized to see the audit
if(isUserAllowToSeeAudit(userId, requestingAuditId))
{
context.Succeed(requirement);
return;
}

context.Fail();
}
private bool isUserAllowToSeeAudit(int userId, Guid auditId)
{
// ...
}

我建议您使用IAuthorizationRequirement和AuthorizationHandler方法。AuthorizationHandler的实例(其中T是必需的(在您的启动中注册为singleton。因此,您可以将IHttpRequestAccessor注入处理程序,使其能够访问请求。这最终变成了类似的东西

public class YourAuthorizationHandler : AuthorizationHandler<YourAuthorizationRequirement>
{
private readonly IHttpContextAccessor _httpContextAccessor;
YourAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, YourAuthorizationRequriement requirement)
{
var userIdInClaim = context.User.Claims.Where(claim => claimType == NameIdentifier).FirstOrDefault();
var request = _httpContextAccessor.HttpContext.Request;
request.EnableBuffering(); // allows the request to be read again
// read the request from request.Body assuming an HTTP POST. It will depend.
// do your logic checking the content here.
return context.Succeed(requirement); // Assuming things are what you want.
}
}

这并不像看上去那么复杂。

阅读以下ASP.NET Core 中的授权简介

您不需要向IAuthorizationRequirement类添加任何额外的参数,也不需要在AuthorizationHandler类中创建额外的构造函数。

您要查找的内容包含在处理程序的AuthorizationHandlerContext context参数中。

特别是,您需要该参数的Resource属性。该值将是特定于框架的,但通常情况下,如果您使用端点路由,您会执行以下操作:

if (context.Resource is HttpContext httpContext)
{
// Whatever you want to do with httpContext
}

使用传统路由或使用MVC的授权过滤器时,Resource的值是一个AuthorizationFilterContext实例,在这种情况下,您可以执行以下操作:

if (context.Resource is AuthorizationFilterContext authFilterContext)
{
var httpContext = authFilterContext.HttpContext
// Whatever you want to do with httpContext
}

相关内容

  • 没有找到相关文章

最新更新