寻找防止恶意数据更改的想法: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();
Run Code Online (Sandbox Code Playgroud)
假设我们知道调用SaveChanges我们的API 的用户的身份,我们如何针对该用户验证我们的实体(新的或修改过的)?
首先想到的是根据用户的身份对实体属性进行子类化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
Run Code Online (Sandbox Code Playgroud)
如果使用这种方法,_currentUserId在新EFContextProvider类的构造函数中建立是否有意义?
一个想法或者更好的方法来解决这个问题?
我认为你走在正确的轨道上.我自己一直在兜售它,并走了很多路.
假设您已经处理了身份验证,并且可以使用身份验证IPrincipal.您也可以自定义一个自定义IIdentity(称之为AppIdentity),您可以在其中存储UserId经过身份验证的用户.
Web Api的基ApiController类IPrincipal通过其User属性使环境可用.我们将在您的自定义Breeze Web Api控制器中利用它,这可能是这样的:
[Authorize]
[JsonFormatter, ODataActionFilter]
public class BreezeApiController : ApiController
{
private readonly AppContextProvider _context;
public BreezeApiController() {
// pass 'User' IPrincipal to the context ctor
_context = new AppContextProvider(User);
}
...
// one of the Query action methods
[HttpGet]
public IQueryable<Foo> Foos() {
return _context.Foos
}
...
您的自定义EFContextProvider可能会像这样开始:
public class AppContextProvider : EFContextProvider<AppDbContext>
{
public AppContextProvider(IPrincipal user)
{
UserId = ((AppIdentity) user.Identity).UserId;
}
public int UserId { get; private set; }
...
现在您可能希望防止UserA看到UserB的实体.因此,不要让每个Foo人都出门,你的自定义EFContextProvider可以相应地过滤.
public DbQuery Foos
{
get
{
// Here the 'Context' is your EF DbContext
return (DbQuery) Context.Foos
.Where(f => f.UserId == UserId);
}
}
回头看一下控制器,我们发现它的FoosGET动作方法对于过滤器一无所知......应该如此.我们希望我们的控制器很轻松,并将业务逻辑移动到自定义EFContextProvider及其帮助程序.
最后,高度简化的通用目的BeforeSaveEntity可能如下所示:
private bool BeforeSaveEntity(EntityInfo info)
{
var entity = info.Entity;
if (info.EntityState == EntityState.Added)
{
entity.UserId = UserId;
return true;
}
return UserId == entity.UserId || throwCannotSaveEntityForThisUser();
}
...
private bool throwCannotSaveEntityForThisUser()
{
throw new SecurityException("Unauthorized user");
}
请注意,服务器上的自定义上下文提供程序负责设置UserId添加的实体.无论如何,我们不会相信客户这样做.当然,它负责验证已UserId修改和已删除的实体.
希望这可以帮助.请记住,这只是一个草图.真正的交易将更加复杂,并被重构为帮助者.
| 归档时间: |
|
| 查看次数: |
360 次 |
| 最近记录: |