如何保持客户数据的隔离

时间:2013-11-26 06:57:35

标签: c# entity-framework cqrs

作为简化示例,我有用户,产品和客户。允许用户访问某些产品和某些客户。

我正在使用edmx文件将我的SQL Server映射到我的代码并使用linq获取数据。典型的查询可能如下所示:

from prod in ctx.Products
join userProduct in ctx.UserProduct
on prod.Id equals userProduct.ProductId

join user in ctx.UserProfile
on userProduct.UserId equals user.Id

where user.UserName == username  // <-- username is a method parameter
select new Product
{
    Id = prod.Id,
    DisplayText = prod.UserFriendlyText
}

每当我需要数据库中的数据时,我必须加入访问权限表,以排除用户无权访问的数据。这意味着如果某人(最终会发生)忘记加入访问表,用户将会看到太多。有没有办法包含数据,以便在忘记访问表时没有显示任何内容?

我一直在考虑将不同的客户分成不同的数据库,因为他们的数据永远不会彼此相关,如果我在客户之间泄露数据,这将是一个小小的灾难。来自同一客户的用户之间的泄漏产品很糟糕,但并不重要。

如果重要的话我在C#MVC4 CQRS架构中,读写端最终保持一致。

我已经检查了类似问题的堆栈溢出,但我能找到的只是未解决的问题:

3 个答案:

答案 0 :(得分:1)

如何使用Repository pattern并强制您的Dev使用它来调用数据库?这将促进代码重用并提高应用程序的可维护性。

因为将从存储库调用方法,您可以控制与数据库交互的代码,并强制一致性,这样您就可以确保始终使用访问表,并根据需要使用。

答案 1 :(得分:0)

我的数据库中存在类似的问题。我的实体中有90%是“依赖组织的”。我的方法使用通用基础存储库,其方法如下:

    public virtual T Find(int id)
    {
        T e = Context.Set<T>().Find(id);

        var od = e as OrganisationDependent;
        if (od != null && od.OrganisationID != CurrentOrganisationID)
            return null;

        if (e == null)
            return null;

        return e;
    }

“全部”方法是一个特殊问题。由How to conditionally filter IQueryable

解决
    private static readonly PropertyInfo _OrganisationIDProperty = ReflectionAPI.GetProperty<OrganisationDependent, int>(o => o.OrganisationID);

    private static Expression<Func<TOrg, bool>> FilterByOrganization<TOrg>(int organizationId)
    {
        //The FilterByOrganisation method uses the LINQ Expressions API to generate an expression that will filter on organisation id
        //This avoids having to cast the set using .AsEnumerable().Cast<OrganisationDependent>().Where(x => x.OrganisationID == CurrentOrganisationID).AsQueryable().Cast<T>();
        //https://stackoverflow.com/questions/20052827/how-to-conditionally-filter-iqueryable-by-type-using-generic-repository-pattern
        var item = Expression.Parameter(typeof(TOrg), "item");
        var propertyValue = Expression.Property(item, _OrganisationIDProperty);
        var body = Expression.Equal(propertyValue, Expression.Constant(organizationId));
        return Expression.Lambda<Func<TOrg, bool>>(body, item);
    }

    public virtual IQueryable<T> All
    {
        get
        {
            if (typeof(T).IsSubclassOf(typeof(OrganisationDependent)))
                return Context.Set<T>().Where(FilterByOrganization<T>(CurrentOrganisationID));

            return Context.Set<T>();
        }
    }

这会关闭用户可以访问其他人数据的大多数地方。但它不会过滤导航属性。因此,我必须向非组织相关实体的所有导航属性添加代码才能执行此操作。

我不想将我的数据分成不同的数据库,但有一天我会发现创建由不同模式中的组织过滤的视图是否可行 - 与我的表具有相同的名称和结构,然后根据用户.....哦,我想为每个新组织自动创建它们,并使用代码优先自动迁移它们....

你可以在这里投票Allow filtering for Include extension method

答案 2 :(得分:0)

如果您使用的是CQRS样式架构,则可以考虑为每个用户提供一个或多个包含他们有权访问的产品/客户的视图模型。

如果您认为自己必须在CQRS的查询端实施逻辑,这表明您做错了。