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?