Архитектура для ограничения доступа DbContext - PullRequest
0 голосов
/ 21 января 2019

В настоящее время я пишу фреймворк отдыха, я хотел бы создать способ ограничения доступа к определенным объектам не только через чтение, но и через запись.В настоящее время я создал базовый 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, это будет невозможно, пока я не создам AuthorizedDbContext, который наследуется от IdentityDbContext<AppUser>

Вместо этого я предпочел бы использовать обертку вокруг их контекста.Например,

//Pseudo-Code
AuthorizedDbContextScope<T>: IDisposable
    where T: DbContext
{
    public void ApplyConstraints()
    {
        this._options.DynamicConstraints.Foreach(EntityFrameWorkZ.ApplyDynamicFilterFromAction)
    }
}

Единственные проблемы с этой оболочкой: 1. Я не могу раскрыть функциональность DbContext, я не могу переопределить изменения сохранения в области действия, я должен заставить пользователя вызывать изменения сохранения в оболочке..

Я мог бы использовать DynamicProxy для наследования от их DbContext при запуске, но это похоже на избыточное убийство, и это сильно замедлило бы запуск проекта.

Если у кого-нибудь есть предложениекак я могу лучше универсально ограничить свои обновления, пожалуйста, дайте мне знать.

Как можно полностью ограничить изменения в БД без ограничения гибкости наследования в коде пользователя?

1 Ответ

0 голосов
/ 21 января 2019

Это субъективно, но я попробую.

  1. Если вы хотите иметь возможность конкретно определять, какие объекты вы хотите авторизовать, вы можете использовать атрибут Authorize. Прошло много времени с тех пор, как я работал с ним, но я вспоминаю возможность настраивать поведение. Если это не сработает, вы можете написать свои собственные и украсить объекты, которые вас интересуют, - либо использовать атрибут для непосредственной авторизации, либо просто использовать его в качестве идентификатора и отразить объект, прежде чем вносить изменения. Это даст вам некоторую гибкость при настройке по домену приложения.
  2. Если это не работает для вас, сколько типов контекстов вы на самом деле пытаетесь настроить? Если это два, а несуществующий третий кажется далеким ... тогда ягни. Если вы пойдете с этим, централизуйте логику авторизации в одном месте и создайте два базовых класса для ее использования. Стоит упомянуть, что IdentityDbContext наследуется от DbContext, так что вы можете обобщать, когда заканчивается авторизация. Или вы можете использовать интерфейс, если вам нужно, чтобы они вели себя по-другому.
  3. Поменяйте местами все ссылки на DbContext с IdentityDbContext, а затем унаследуйте его с вашими настройками. Опять же, DbContext является корнем IdentityDbContext. Я не помню, чтобы при использовании одного из них были значительные издержки, но это может зависеть от вашего домена.

Все эти идеи могут быть ограничены тем, как разработано ваше решение и будет ли эта функциональность использоваться одним или несколькими приложениями.

...