拒绝用户访问以查看其他用户的数据

时间:2016-04-06 15:39:00

标签: angularjs asp.net-core

我在ASP.NET Core中使用Angular和ASP.NET Identity应用程序。

我有以下控制器操作

[HttpGet("users/{userId:int:min(1)}/notes"), Authorize]
public async Task<IActionResult> GetNotesBy(userId) {

   var data = _service.getNotesBy(userId);
   return Ok(data);

} // GetNotesBy

我想限制对API的访问:

如果用户通过身份验证,则只能访问其备注。 我想阻止ID = X的身份验证用户访问ID = Y的用户的注释。在这种情况下如何阻止用户?

1 个答案:

答案 0 :(得分:3)

这是基于资源的授权的目标。

由于基于资源的授权需要在控制器内部强制执行所需的实际资源。

以下内容适用于ASP.NET Core RC1。

所以,我们假设你的getNotesBy返回一个Notes类,你有一些操作,读,写,更新,删除。

首先我们需要定义操作。 Microsoft.AspNet.Authorization.InfrastructureOperationAuthorizationRequirement中有一个合适的基类。所以我们会做这样的事情。

public static class Operations
{
    public static OperationAuthorizationRequirement Create = 
        new OperationAuthorizationRequirement { Name = "Create" };
    public static OperationAuthorizationRequirement Read = 
        new OperationAuthorizationRequirement   { Name = "Read" };
    public static OperationAuthorizationRequirement Update = 
        new OperationAuthorizationRequirement { Name = "Update" };
    public static OperationAuthorizationRequirement Delete = 
        new OperationAuthorizationRequirement { Name = "Delete" };
}

现在我们有了我们的业务,我们考虑如何处理授权。如果当前用户拥有笔记,或者当前用户是管理员,则操作可以有两种方式成功。这相当于单个需求/操作的两个处理程序。

管理员很容易,看起来像这样;

public class AdminAuthorizationHander : 
    AuthorizationHandler<OperationAuthorizationRequirement, Notes>
{
    protected override void Handle(AuthorizationContext context, 
                                   OperationAuthorizationRequirement requirement, 
                                   Document resource)
    {
        var isSuperUser = context.User.FindFirst(c => c.Type == "Superuser" &&
                                                      c.Value == "True");
        if (isSuperUser != null)
        {
            context.Succeed(requirement);
            return;
        }
    }
}

这里我们正在寻找值为True的超级用户声明。如果现在我们成功了这个要求。您可以从方法签名中看到我们正在使用OperationAuthorizationRequirement和一个资源Notes类。此处理程序不会将自身限制为单个操作,管理员对每个操作都有权限。

现在我们可以编写查找实际用户的处理程序。

public class NotesAuthorizationHandler : 
    AuthorizationHandler<OperationAuthorizationRequirement, Notes>
{
    protected override void Handle(AuthorizationContext context, 
                                   OperationAuthorizationRequirement requirement, 
                                   Notes resource)
    {
        if (context.User.Name == resource.Owner)
        {
            context.Succeed(requirement);
        }
    }
}

这里我们正在编写适用于所有资源的内容,并根据当前用户的名称检查资源上的Owner属性。

因此,我们现在有两个处理程序用于单个要求,OperationAuthorizationRequirement

现在我们需要注册我们的处理程序。在startup.cs中,您在ConfigureServices()方法中在DI中注册处理程序。致电services.AddAuthorization()后,您需要将处理程序放入DI中。你会这样做;

services.AddSingleton<IAuthorizationHandler, AdminAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, NotesAuthorizationHandler>();

如果您正在使用Singleton之类的内容,则可以将范围从DbContext调整为您喜欢的范围。

最后我们几乎准备好调用它,但首先你需要更改控制器构造函数以获取IAuthorizationService的实例。完成后,您可以致电AuthorizeAsync()然后离开。

[Authorize]
public class NotesController : Controller
{
    IAuthorizationService _authorizationService;

    public NotesController(IAuthorizationService authorizationService)
    {
        _authorizationService = authorizationService;
    }

    [HttpGet("users/{userId:int:min(1)}/notes"), Authorize]
    public async Task<IActionResult> GetNotesBy(userId) 
    {
        var resource = _service.getNotesBy(userId);

        if (await authorizationService.AuthorizeAsync(User, resource, Operations.Read))
        {
            return Ok(data);
        }

        return new ChallengeResult();
    }
}

所以你正在做的是获取你的资源,然后根据它和操作授权当前用户。发生这种情况时,将调用可以处理该资源和操作的所有处理程序。由于有多个处理程序,任何人都可以成功并允许访问。