如何在 ASP.NET Core 2.2 中正确进行基于资源的授权?

Tra*_*Fox 5 authorization asp.net-core

我有一个 ASP.NET Core 2.2 应用程序,在其中显示一些文档。大多数文档都是公开的,因此匿名访问是可以的。但是,某些文档是私有的(即它们需要身份验证/授权),并且将来某些文档可能还需要有效的订阅。所有文档都使用相同的操作进行检索,因此我们只有在加载文档后才知道所需的权限。我们还加载一些资源作为静态文件(IApplicationBuilder.UseStaticFiles),但我想这实际上不应该成为问题,因为StaticFileOptions.OnPrepareResponse可以用于自定义授权代码。

目前谁可以访问私人文档的逻辑非常简单。目前,我们只显示文档,不允许对其进行任何其他类型的操作(编辑、删除等)。对我来说,这听起来像是基于资源的授权的一个非常标准的案例。

不管怎样,我找到了这篇文章,根据我的理解,我需要定义一个策略(由一个神奇的字符串标识 - 这是怎么回事?!)以及一个要求和一个AuthorizationHandler<MyRequirement, MyResource>将执行实际授权逻辑的要求。然后,在我的控制器操作中,我需要调用IAuthorizationService.AuthorizeAsync并传递用户、资源和策略名称(魔术字符串),并根据该方法的结果允许或拒绝访问。对于我想要完成的任务来说,这似乎更加复杂。如果我简单地定义自己的“授权服务”并简单地删除整个策略和要求内容,可能会更容易。我还认为,我必须在所有受影响的控制器操作中复制 if-else 逻辑,这不太理想。

当然我不是唯一一个有这个问题的人。有什么我错过的吗?如果确实有充分的理由使用政策和要求,那么在这种情况下您会如何命名它们?我真的感觉有点失落。也许使用文档类型(公共、私有、仅限订阅者)作为策略名称有意义?

win*_*rs0 0

我推荐本文中解释的最后一种方法 - https://www.red-gate.com/simple-talk/dotnet/c-programming/policy-based-authorization-in-asp-net-core-a-deep-潜水/

允许您通过仅应用带有策略名称的注释来保持控制器清洁。在处理程序中,您必须实现逻辑检查人员是否可以访问资源 - 例如,它可以基于检查资源中的属性所有者 ID(例如在数据库表列中)或 AD 中某个组的成员,或任何其他内容别的。

编辑:

使用需求和需求处理程序 - 我做了类似的事情。我不知道你的逻辑到底应该如何运作,所以我只是假设一些。

假设您有一个获取端点:documents/documentId

您想要应用逻辑,使该文档仅可供文档所有者访问。显然,您需要在某个地方存储文档的所有者,因此让我们将其保留在文档实体的属性中。

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, IsDocumentOwner requirement, DocumentRepository documentRepository)
{
    if (context.Resource is AuthorizationFilterContext ctx)
    {
        var documentId = ctx.RouteData.Values["documentId"]?.ToString();

        //here load document from repo and check if the property ownerId is equal to current user id

        var userId = context.User.Claims.FirstOrDefault(x => x.ToString().Contains(oid))?.Value;
        //if yes, make the request pass to the body of a controller with the attribute
        context.Succeed(requirement);
    }

}
Run Code Online (Sandbox Code Playgroud)

实现 IsDocumentOwner:

public class IsDocumentOwner : IAuthorizationRequirement 
    {
    }
Run Code Online (Sandbox Code Playgroud)

在您的 Startup.cs 中添加:

services.AddAuthorization(options =>
            {
                options.AddPolicy(
                    nameof(IsDocumentOwner),
                    policyBuilder => policyBuilder.AddRequirements(
                        new IsDocumentOwner()));
            });
Run Code Online (Sandbox Code Playgroud)

然后,最后一步,在控制器方法上应用属性

[Authorize(Policy = "IsDocumentOwner")]
[HttpGet("{documentId}")]
public YourDocumentObjectResultClass GetDocument([FromRoute]string documentId)
{
//stuff you do when current user is owner of the document, probably just display the doc
}
Run Code Online (Sandbox Code Playgroud)

对于 IsDocumentOwner 处理程序,您可以通过构造函数注入任何服务(由上面的存储库可视化),例如,检查用户是否是 azure ad 上的组的成员