作为简化示例,我有用户,产品和客户。允许用户访问某些产品和某些客户。
我正在使用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架构中,读写端最终保持一致。
我已经检查了类似问题的堆栈溢出,但我能找到的只是未解决的问题:
答案 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>();
}
}
这会关闭用户可以访问其他人数据的大多数地方。但它不会过滤导航属性。因此,我必须向非组织相关实体的所有导航属性添加代码才能执行此操作。
我不想将我的数据分成不同的数据库,但有一天我会发现创建由不同模式中的组织过滤的视图是否可行 - 与我的表具有相同的名称和结构,然后根据用户.....哦,我想为每个新组织自动创建它们,并使用代码优先自动迁移它们....
答案 2 :(得分:0)
如果您使用的是CQRS样式架构,则可以考虑为每个用户提供一个或多个包含他们有权访问的产品/客户的视图模型。
如果您认为自己必须在CQRS的查询端实施逻辑,这表明您做错了。