Aplicativo MultiTenant impede dados de acesso de inquilino de outro inquilino no banco de dados compartilhado

Estou trabalhando em um aplicativo de inquilino e queria saber como posso bloquear o acesso do inquilino a outros dados do inquilino.

Primeiro, deixe-me expor alguns fatos:

O aplicativo não é gratuito, 100% com certeza o usuário mal-intencionado é um cliente.Todas as chaves primárias / identidade são números inteiros (a Guid resolve esse problema, mas não podemos mudar no momento).O aplicativo usa banco de dados compartilhado e esquema compartilhado.Todos os inquilinos são grupos empresariais que possuem várias lojas.Estou usando falsificação ...

eu tenho algunsdados remotos Escolhido porsuspenso e é fácil alterar os IDs e os dados de acesso de outros inquilinos, se você tiver um pouco de conhecimento, poderá recuperar dados de outros inquilinos.

A primeira coisa que acho foi verificar todos os campos remotos, mas isso é meio irritante ...

Então, eu construo uma solução compatível comCode First Migrations usandoConvenção modelo eChaves compostas, poucos testados, funcionando conforme o esperado.

Aqui está a solução:

Classe de Convenção

public class TenantSharedDatabaseSharedSchemaConvention<T> : Convention where T : class
{
    public Expression<Func<T, object>> PrimaryKey { get; private set; }

    public Expression<Func<T, object>> TenantKey { get; private set; }

    public TenantSharedDatabaseSharedSchemaConvention(Expression<Func<T, object>> primaryKey, Expression<Func<T, object>> tenantKey)
    {
        this.PrimaryKey = primaryKey;
        this.TenantKey = tenantKey;

        base.Types<T>().Configure(m =>
        {
            var indexName = string.Format("IX_{0}_{1}", "Id", "CompanyId");

            m.Property(this.PrimaryKey).IsKey().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnOrder(0).HasColumnAnnotation("Index", new IndexAnnotation(new[] {
                new IndexAttribute(indexName, 0) { IsUnique = true }
            }));

            m.Property(this.TenantKey).IsKey().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None).HasColumnOrder(1).HasColumnAnnotation("Index", new IndexAnnotation(new[] {
                new IndexAttribute(indexName, 1) { IsUnique = true }
            }));
        });
    }
}

Registro de convenção:

** No registro de convenção, passo duas propriedades: primeiro a chave primária e o segundo é o ID do inquilino.

modelBuilder.Conventions.Add(new TenantSharedDatabaseSharedSchemaConvention<BaseEntity>(m => m.Id, m => m.CompanyId));

Modelo de entidade base

public class BaseEntity
{
    public int Id { get; set; }

    public int CompanyId { get; set; }

    public Company Company { get; set; }
}

Entidade do pedido (exemplo)

** Aqui faço referência à moeda e ao cliente com a empresa e todos funcionam como esperado ...

public class Order : BaseEntity
{
    [Required]
    public int CurrencyId { get; set; }

    [ForeignKey("CompanyId, CurrencyId")]
    public virtual Currency Currency { get; set; }

    [Required]
    public int ClientId { get; set; }

    [ForeignKey("CompanyId, ClientId")]
    public virtual Client Client { get; set; }

    public string Description { get; set; }
}
Existe algum impacto no desempenho?Existe alguma desvantagem em comparação a verificar todos os campos remotos?Alguém tem a mesma ideia e / ou problema e veio com outra solução?

questionAnswers(1)

yourAnswerToTheQuestion