让我们有下列实体系统:用于对实体控制访问ASP.MVC最佳安全实践
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; }
}
我们也有要求:
- 医生应该可以编辑自己的食谱
- 医生应该能看到他的部门
- 医生内医生只食谱应该能够提供的食谱 进行搜索
- 医生应该能够提供的食谱来生成报告的详细信息
现在我实现了以下安全检查:
public void ValidateAccess(Doctor doctor, Recipe aRecipe, EntityAction action)
{
if (action == EntityAction.Modify && doctor.ID == aRecipe.Doctor.ID)
return;
if (action == EntityAction.Read && doctor.DepartmentID == aRecipe.Doctor.DepartmentID)
return
throw new SecurityException();
}
这工作适合简单的方法,当我有receipe实体,我可以通过在我的逻辑方法开始时调用此方法来轻松验证访问。
但现在我有问题,该解决方案将无法搜索,当我没有确切的实体,而是对他们的一些统计上报工作。
让我们想象,我要生成患者的名为“aName”是有分量“someGuid” receipes报告,我会有一些查询与2个标准:
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);
的问题是,我应该在系统中,这部分添加到每个查询它对信息进行任何计算。
更新(2012年11月12日):
第一个例子是非常简单的,并且StuartLC在他的帖子中提到的可以解决的。 但是我们的系统中有更复杂的报告。例如 - 显示所有患者的食谱中含有某种guid的患者。 现在我们的查询从另一个存储库开始,所以我们不能应用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)));
结束时更新。
什么模式或做法可以适用于使该解决方案更容易,并防止复制粘贴表达每个查询? 我会感谢您的回答和建议。
难道不应该是术士和药水,医生和处方,或厨师和食谱? – Tr1stan
可能是你对的域名,实体应该是处方...我会考虑它,但问题是关于访问限制。 –
当然,我只是没有帮助,有时经过漫长的一天后...... – Tr1stan