Asp.net mvc ASP.MVC控制实体访问的最佳安全实践
让我们拥有具有以下实体的系统:Asp.net mvc ASP.MVC控制实体访问的最佳安全实践,asp.net-mvc,entity-framework,security,architecture,Asp.net Mvc,Entity Framework,Security,Architecture,让我们拥有具有以下实体的系统: public class Doctor { public int ID { get; set; } public int DepartmentID { get; set; } public string Name { get; set; } public ICollection<Recipe> Recipes { get; set; } } public class Patient { public int I
public class Doctor
{
public int ID { get; set; }
public int DepartmentID { get; set; }
public string Name { get; set; }
public ICollection<Recipe> Recipes { get; set; }
}
public class Patient
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Recipe> Recipes { get; set; }
}
public class Recipe
{
public int ID { get; set; }
public int DoctorID { get; set; }
public int PatientID { get; set; }
public Doctor Doctor { get; set; }
public Patient Patient { get; set; }
public ICollection<RecipeDetails> Details { get; set; }
}
public class RecipeDetails
{
public int ID { get; set; }
public Guid SomeGuid { get; set; }
public double SomeValue { get; set; }
}
当我有receipe实体时,这非常适合于简单的方法,我可以在逻辑方法开始时通过校准此方法来轻松验证访问
但现在我遇到了问题,当我没有确切的实体但有一些关于它们的统计数据时,这个解决方案将不适用于搜索和报告
假设我想为名为“aName”的患者生成报告,这些患者的receipes组件为“someGuid”,我将使用两个标准进行查询:
var res = RecipeRepository.Query(r => aName.Contains(r.Patient.Name)).SelectMany(r => r.Details).Where(d => d.SomeGuid == someGuid).Sum(d => d.SomeValue);
此查询不正确,它将显示所有配方的统计信息,包括应隐藏的配方。
要解决这个问题,我们应该将访问条件添加到查询中:
currentDoctor.DepartmentID == r.Doctor.DepartmentID
所以现在我有一个疑问:
var res = RecipeRepository.Query(r => aName.Contains(r.Patient.Name) && currentDoctor.DepartmentID == r.Doctor.DepartmentID).SelectMany(r => r.Details).Where(d => d.SomeGuid == someGuid).Sum(d => d.SomeValue);
问题是,我应该将此部分添加到系统中对receipes进行任何计算的每个查询中
更新(2012年11月12日):
第一个例子非常简单,可以像斯图尔特在他的帖子中提到的那样解决。
但我们的系统中有更复杂的报告。例如,显示配方中含有成分someGuid的所有患者。
现在,我们的查询从另一个存储库开始,因此我们不能从RecipeRepository应用私有或受保护的方法。
以下是示例查询:
var res = PatientRepository.Query(p => p.Name.Contains(aName) && p.Recipes.Any(r => r.Details.Any(d => d.SomeGuid == someGuid)));
在这种情况下,我们仍然需要将过滤器直接添加到查询中:
var res = PatientRepository.Query(p => p.Name.Contains(aName) && p.Recipes.Any(r => currentDoctor.DepartmentID == r.Doctor.DepartmentID && r.Details.Any(d => d.SomeGuid == someGuid)));
结束更新
可以应用什么模式或实践来简化此解决方案并防止将表达式复制粘贴到每个查询?
非常感谢您的回答和建议。如果您的存储库模式
Query()
方法返回一个非物化的IQueryable
,那么您可以将数据访问限制问题重构为助手方法,每个“可限制”实体对应一个方法,例如:
private IQueryable<Recipe> ApplyAccessFilters(IQueryable<Recipe> query, User user)
{
IQueryable<Recipe> filteredQuery = query;
// Custom method to determine if user is restricted to just his / her recipes
if (!CheckUserPermission(currentUser, Access.MaySeeAllRecipies) ))
{
filteredQuery = filteredQuery
.Where(r => r.DepartmentId = currentUser.DepartmentId)
} // Else no restriction, e.g. Admin Users can access all recipes
// Other access related filters here
return filteredQuery;
}
您可以用同样的方法处理其他问题,例如分页
甚至更好的是,您可以制作这个访问过滤器,在这种情况下,过滤器很容易吸引眼球:
return View(RecipeRepository
.Query(r => r.SomeFields == someFilters)
.ApplyAccessFilters(currentUser)
.Paginate(pagingInfo)
.AsEnumerable());
如果您的存储库模式
Query()
方法返回一个非物化的IQueryable
,那么您可以将数据访问限制问题重构为助手方法,每个“可限制”实体对应一个方法,例如:
private IQueryable<Recipe> ApplyAccessFilters(IQueryable<Recipe> query, User user)
{
IQueryable<Recipe> filteredQuery = query;
// Custom method to determine if user is restricted to just his / her recipes
if (!CheckUserPermission(currentUser, Access.MaySeeAllRecipies) ))
{
filteredQuery = filteredQuery
.Where(r => r.DepartmentId = currentUser.DepartmentId)
} // Else no restriction, e.g. Admin Users can access all recipes
// Other access related filters here
return filteredQuery;
}
您可以用同样的方法处理其他问题,例如分页
甚至更好的是,您可以制作这个访问过滤器,在这种情况下,过滤器很容易吸引眼球:
return View(RecipeRepository
.Query(r => r.SomeFields == someFilters)
.ApplyAccessFilters(currentUser)
.Paginate(pagingInfo)
.AsEnumerable());
这不应该是术士和药水,医生和处方,或厨师和食谱吗?也许你们关于域名的看法是对的,实体应该是处方。。。我会考虑的,但问题是关于访问限制。当然,我只是无济于事,有时会在漫长的一天之后发生……这不应该是术士和药剂,医生和处方,或者厨师和食谱吗?也许你关于域名的看法是对的,实体应该是处方。。。我会考虑的,但问题是关于访问限制。当然,我只是无济于事,有时会在漫长的一天之后发生……谢谢你的回答。它适用于所有从Recipereposition开始的查询,但这并不总是正确的。我需要一些更通用的解决方案,即使查询是从另一个存储库启动的,并且配方在查询中,也可以应用这些解决方案。。。我会在我的问题中考虑更好的说明。我在我的问题中又添加了一个例子,请看一看,并告诉我你对此的看法。谢谢你的回答。它适用于所有从Recipereposition开始的查询,但这并不总是正确的。我需要一些更通用的解决方案,即使查询是从另一个存储库启动的,并且配方在查询中,也可以应用这些解决方案。。。在我的问题中,我会考虑更好的说明。我在我的问题中又添加了一个例子,请看一下,并告诉我你对此有何看法。