【问题标题】:Global Resource Authorization based on route value基于路由值的全局资源授权
【发布时间】:2020-06-18 13:24:31
【问题描述】:

我正在开发一个 ASP.Net Core 3.1 Web API。

API 用户来自 Azure AD。 用户如果有许可证就可以访问API,每个用户可以分配多个许可证,同一个许可证可以分配给多个用户。

客户希望我使用 <api_url>/{licenseId}/controller/action 之类的模板来构建 API 路由。

我的控制器是这样的:

[Authorize]
[Route("{licenseId}/Foo")]
public class FooController : ControllerBase
{

如果我将许可证视为资源,我可以使用基于资源的授权,详细说明为here。 它有效,但我发现自己复制并粘贴了所有操作的身份验证检查。

有没有更好的方法来授权用户使用路由值?

这是我到目前为止所得到的:

public class LicenseRequirement : IAuthorizationRequirement
{        
    public Guid LicenseId { get; private set; }

    public LicenseRequirement(Guid licenseId)
    {
        LicenseId = licenseId;
    }
}

public class LicenseAuthorizationHandler : AuthorizationHandler<LicenseRequirement>
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly ILogger<LicenseAuthorizationHandler> _logger;
    private readonly DBContext _db;

    public LicenseAuthorizationHandler(DBContext context, ILogger<LicenseAuthorizationHandler> logger, IHttpContextAccessor httpContextAccessor)
    {
        _logger = logger;
        _db = context;
        _httpContextAccessor = httpContextAccessor;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, LicenseRequirement requirement)
    {
        var userId = new Guid(context.User.GetUserId());
        var licenseId = _httpContextAccessor.HttpContext.GetRouteData().Values["licenseId"];

        if (await _db.ApiUsers.SingleOrDefaultAsync(x => x.LicenseId == new Guid(licenseId as string) && x.UserId == userId) is ApiUser user)
            context.Succeed(requirement);
    }
}

现在我有点卡住了,因为我不知道如何在 Startup.cs 中设置它并将其用作属性或区域过滤器,在运行时使用 licenseId 路由的值创建这些要求。

【问题讨论】:

    标签: c# asp.net-core routes asp.net-core-webapi asp.net-authorization


    【解决方案1】:

    我发现IAuthorizationFilter 实现起来非常简单。当我昨天尝试时,我找不到 RouteValues 但他们在那里:

    public class LicenseAuthorizationFilter : IAuthorizationFilter
    {
        private readonly ILogger<LicenseAuthorizationFilter> _logger;
        private readonly DBContext _db;
    
        public LicenseAuthorizationFilter(DBContext context, ILogger<LicenseAuthorizationFilter> logger)
        {
            _logger = logger;
            _db = context;
        }
    
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var userId = new Guid(context.HttpContext.User.GetUserId());
            var licenseId = new Guid(context.HttpContext.Request.RouteValues["licenseId"] as string);
    
            if (!(_db.ApiUsers.SingleOrDefault(x => x.LicenseId == licenseId && x.UserId == userId) is ApiUser user))
            {
                context.Result = new ForbidResult();
            }
        }
    }
    
    public class LicenseAuthorizationAttribute : TypeFilterAttribute
    {
        public LicenseAuthorizationAttribute() : base(typeof(LicenseAuthorizationFilter))
        { }
    }
    

    控制器可以整齐地变成:

    [Authorize]
    [LicenseAuthorization]
    [Route("{licenseId}/Items")]
    public class ItemsController : ControllerBase
    {
        [...]
    }
    

    【讨论】:

      猜你喜欢
      • 2015-03-23
      • 2023-03-25
      • 2013-09-22
      • 2021-08-31
      • 2019-07-18
      • 1970-01-01
      • 2014-09-12
      • 1970-01-01
      • 2021-12-28
      相关资源
      最近更新 更多