3

寻找防范恶意数据更改的想法:userA 操作(编辑或删除)属于 userB 的数据。由于我们在客户端上创建实体,我们需要将它们(或至少其中一些)分配给经过身份验证的用户。

例如:

var newItem = ds.createNewItem();
newItem.OwnerId(22); //this is the problem that I see.    
newItem.Name("New Item");
newItem.Description("I just changed your item!");
... //and so on
ds.saveChanges();

假设我们知道调用我们 API 的用户的身份,SaveChanges我们如何针对该用户验证我们的实体(新的或修改的)?

想到的第一个想法是根据我们用户的身份继承EFContextProvider、覆盖BeforeSaveEntity和检查实体属性。OwnerId例如:

if (entityInfo.Entity.GetType() == typeof(Item)
    && (entityInfo.EntityState == EntityState.Added 
    || entityInfo.EntityState == EntityState.Modified)
    && ((Item)entityInfo.Entity).OwnerId != _currentUserId) {
    return false
    ... //and so on

_currentUserId如果使用这种方法,在我们的新类的构造函数中建立是否有意义EFContextProvider

解决这个问题的想法或更好的方法?

4

1 回答 1

5

我认为你在正确的轨道上。我自己一直在研究这个,并且走上了同样的道路。

假设您已经处理了身份验证并且有一个IPrincipal可用的。您也有自己的自定义IIdentity(称为它AppIdentity),您可以在其中UserId为经过身份验证的用户存储。

Web Api 的基类通过其属性ApiController使环境IPrincipal可用。User我们将在您的自定义 Breeze Web Api 控制器中利用它,它可能会像这样开始:

[授权]
[JsonFormatter,ODataActionFilter]
公共类 BreezeApiController : ApiController
{
    私有只读 AppContextProvider _context;

    公共 BreezeApiController() {
        // 将 'User' IPrincipal 传递给上下文 ctor
        _context = new AppContextProvider(User);
    }

    ...

    // 查询操作方法之一
    [HttpGet]
    公共 IQueryable<Foo> Foos() {
        返回 _context.Foos
    }

    ...

您的自定义EFContextProvider可能会像这样开始:

公共类 AppContextProvider : EFContextProvider<AppDbContext>
{
    公共 AppContextProvider(IPrincipal 用户)
    {
        UserId = ((AppIdentity) user.Identity).UserId;
    }

    公共 int 用户 ID { 获取;私人套装;}
    ...

现在您可能想要阻止 UserA 看到 UserB 的实体。因此,您的自定义可以相应地过滤,而不是让每个Foo人都出门。EFContextProvider

   公共 DbQuery Foos
   {
       得到
       {
           // 这里的 'Context' 是你的 EF DbContext
           返回 (DbQuery) Context.Foos
               .Where(f => f.UserId == UserId);
       }
   }

回头看控制器,我们看到它的FoosGET 操作方法忽略了过滤器......正如它应该的那样。我们希望我们的控制器是轻量级的,并将业务逻辑移至自定义EFContextProvider及其助手。

最后,高度简化的通用用途BeforeSaveEntity可能如下所示:

私有 bool BeforeSaveEntity(EntityInfo 信息)
{
    var entity = info.Entity;
    如果(info.EntityState == EntityState.Added)
    {
        实体.用户 ID = 用户 ID;
        返回真;
    }
    返回 UserId == entity.UserId || throwCannotSaveEntityForThisUser();
}

...

私人布尔 throwCannotSaveEntityForThisUser()
{
    throw new SecurityException("未经授权的用户");
}

请注意,服务器上的自定义上下文提供程序负责设置UserId添加的实体。无论如何,我们都不相信客户会这样做。当然,它负责验证UserId修改和删除的实体。

希望这可以帮助。请记住,这只是一个草图。真正的交易将更加复杂,并被重构为助手。

于 2012-11-28T09:37:29.850 回答