我有一个ASP.NET Core 2.2应用程序,其中正在显示一些文档。大多数文档是公开的,因此可以匿名访问。但是,某些文档是私有的(即它们需要身份验证/授权),将来某些文档可能还需要有效的订阅。使用相同的操作检索所有文档,因此我们仅在加载文档后知道所需的权限。我们还将某些资源作为静态文件(IApplicationBuilder.UseStaticFiles
加载,但是我想这应该不是一个问题,因为StaticFileOptions.OnPrepareResponse
可以用于自定义授权代码。
当前谁可以访问私有文档的逻辑非常简单。目前,我们仅显示文档,不允许对其进行任何其他类型的操作(编辑,删除等)。对我来说,这听起来像是基于资源的授权的标准案例。
无论如何,我发现了this article,根据我的理解,我需要定义一个策略(由魔术字符串标识-这是怎么回事?!),需求和{ 1}},它将执行实际的授权逻辑。然后,在控制器操作中,我将需要调用AuthorizationHandler<MyRequirement, MyResource>
并向用户传递资源和策略名称(魔术字符串),并根据该方法的结果,允许或拒绝访问。对于我要完成的工作,这似乎使我感到困惑。如果我简单地定义自己的“授权服务”并简单地删除整个策略和要求之类的东西,可能会更容易。我还认为,必须在所有受影响的控制器操作中复制if-else逻辑,这并不理想。
当然我不是唯一一个遇到此问题的人。有什么我想念的吗? 如果确实有充分的理由使用策略和要求,那么在这种情况下如何命名?我真的有点失落。 使用文档类型(公共,私有,仅订阅者)作为策略名称也许有意义?
答案 0 :(得分:0)
我建议本文中介绍的最后一种方法-https://www.red-gate.com/simple-talk/dotnet/c-programming/policy-based-authorization-in-asp-net-core-a-deep-dive/
仅使用带有策略名称的注释即可使控制器保持清洁。在处理程序中,您必须实现逻辑检查人员是否可以访问资源-例如,它可以基于检查资源中的属性ownerId(例如,在数据库表列中)或AD中某个组的成员,或执行任何操作其他。
编辑:
使用Requirements和RequirementsHandlers-我做了类似的事情。 我不知道您的逻辑应该如何工作,所以我将假设一些。
让我们说您有一个get端点: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);
}
}
实现IsDocumentOwner:
public class IsDocumentOwner : IAuthorizationRequirement
{
}
在您的Startup.cs中添加:
services.AddAuthorization(options =>
{
options.AddPolicy(
nameof(IsDocumentOwner),
policyBuilder => policyBuilder.AddRequirements(
new IsDocumentOwner()));
});
然后,最后一步,将属性应用于控制器方法
[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
}
对于您的IsDocumentOwner处理程序,您可以按构造函数注入任何服务(由上面的存储库可视化),例如,检查用户是否是天蓝色广告组的成员
答案 1 :(得分:0)
最后,我们不想处理这些东西,只是编写了自己的AuthorizationService,它像任何其他服务一样注入到控制器中。 它将在首次使用时为所有文档加载所需的权限并对其进行缓存。 我们的控制器方法如下所示:
[HttpGet("[action]")]
public async Task<Document> GetDocument(string documentId)
{
if (_authorizationService.MayAccess(User, documentId))
{
return _documentRepository.GetDocument(documentId);
}
else
{
Response.StatusCode = StatusCodes.Status403Forbidden;
return null;
}
}