限制DbContext访问的体系结构

时间:2019-01-21 00:33:39

标签: c# entity-framework .net-core authorization dbcontext

我目前正在编写一个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过正,这会严重降低项目启动速度。

如果有人对我可以如何更好地普遍限制我的更新提出建议,请告诉我。

如何在不限制用户代码继承灵活性的情况下完全限制数据库更改?

1 个答案:

答案 0 :(得分:0)

这是主观的,但我会试一试。

  1. 如果要专门定义要授权的实体,可以使用Authorize属性。自从我使用它已经有一段时间了,但是我记得自定义行为的能力。如果这不起作用,则可以编写自己的装饰并修饰您关心的实体-使用该属性直接处理授权,或者简单地将其用作标识符并在提交更改之前对对象进行反映。这将给您一些灵活性,可以按应用程序域进行自定义。
  2. 如果这对您不起作用,您实际上是在尝试自定义几种类型的上下文?如果是两个,那么不存在的第三个似乎还很遥远……那么,yagni。如果这样做,可以将授权逻辑集中在一个地方,并创建两个基类来使用它。值得一提的是,IdentityDbContext继承自DbContext,因此您可以在授权终止的地方进行概括。或者,如果需要它们表现不同,则可以使用界面。
  3. 使用IdentityDbContext交换对DbContext的所有引用,然后通过自定义从中继承。同样,DbContext是IdentityDbContext的根。我不记得使用一个与另一个相比会产生大量开销,但是可能取决于您的域。

所有这些想法都可能受解决方案的体系结构以及一个或多个应用程序使用该功能的限制。