我目前正在编写一个rest框架,我想创建一种方法来不仅限制通过读取而且还可以通过写入来限制对某些实体的访问。当前,我已经创建了一个基本的DbContext,它可以像这样处理授权(我省略了一些代码,例如选项分配,因为它们与问题无关):
public abstract class AuthorizedDbContext : DbContext
{
//...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var constraintOptions = this._authorizationOptions.ConstraintOptions;
constraintOptions.ApplyStaticConstraint(modelBuilder, this);
base.OnModelCreating(modelBuilder);
}
public async override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
this.VerifyResourceAccess();
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
protected void VerifyResourceAccess()
{
if (false == ChangeTracker.HasChanges())
{
return;
}
//WARNING: if you don't set the change tracking behavior to no tracking, you could reload entities by accident
var previousTrackingBehavior = this.ChangeTracker.QueryTrackingBehavior;
this.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
this._authorizationOptions.ContextValidator.ValidateAndThrow(this);
this.ChangeTracker.QueryTrackingBehavior = previousTrackingBehavior;
}
}
目前,我注入了一个dbcontext验证器,该验证器用于处理限制更新和有关保存更改的其他验证。
用户放心,知道使用此授权上下文时,如果不通过用户在其代码中定义的所有验证,就无法更新实体。
尽管如此,该体系结构很烂,并且严重限制了用户代码的灵活性,例如,如果用户想使用IdentityDbContext,除非我创建从IdentityDbContext<AppUser>
继承的AuthorizedDbContext,否则将无法实现
相反,我宁愿使用围绕它们的上下文的包装器。例如
//Pseudo-Code
AuthorizedDbContextScope<T>: IDisposable
where T: DbContext
{
public void ApplyConstraints()
{
this._options.DynamicConstraints.Foreach(EntityFrameWorkZ.ApplyDynamicFilterFromAction)
}
}
此包装器的唯一问题是1.我无法公开DbContext功能,不能覆盖范围内的保存更改,我必须强制用户在包装器上调用保存更改。
我可以在启动时使用DynamicProxy从其DbContext继承,但这似乎有些矫over过正,这会严重降低项目启动速度。
如果有人对我可以如何更好地普遍限制我的更新提出建议,请告诉我。
如何在不限制用户代码继承灵活性的情况下完全限制数据库更改?
答案 0 :(得分:0)
这是主观的,但我会试一试。
所有这些想法都可能受解决方案的体系结构以及一个或多个应用程序使用该功能的限制。