4

这是我的第一个问题在stackoverflow,所以请温柔。我正在使用MVC4,Entity Framework和SimpleMembership写入一个仓库应用程序的客户门户。仓库为多家公司提供内容。每个公司都有分部和部门。用户将拥有不同的公司,部门和部门信息。我正在寻找一个优雅的访问控制解决方案。到目前为止,我的模型是这样的:实现公司,部门,部门MVC4用户访问控制与EF

public class UserProfile 
{ 
    UserProfile() 
    { 
     this.AccessControl = new HashSet<AccessControl>(); 
    } 

    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 
    public Nullable<int> CompanyId { get; set; } 
    public virtual ICollection<AccessControl> { get; set; } 
    public virtual Company Company { get; set; } 
} 

public class AccessControl 
{ 
    public int AccessControlId { get; set; } 
    public int UserId { get; set; } 
    public int CompanyId { get; set; } 
    public Nullable<int> DivisionId { get; set; } 
    public Nullable<int> DepartmentId { get; set; } 
    public Boolean ReadAccess { get; set; } 
    public Boolean WriteAccess { get; set; } 

    // other properties for access control 

    public virtual UserProfile UserProfile { get; set; } 
    public virtual Company Company { get; set; } 
    public virtual Division Division { get; set; } 
    public virtual Department Department { get; set; } 
} 

public class Content 
{ 
    public int ContentId { get; set; } 
    public int CompanyId { get; set; } 
    public int DivisionId { get; set; } 
    public int DepartmentId { get; set; } 

    // Various other properties 

    public virtual Company Company { get; set; } 
    public virtual Division Division { get; set; } 
    public virtual Department { get; set; } 
} 

我的想法是,一个空司意味着所有部门和空指部各部门。我的问题是:

  1. 是编写库方法来检索内容对象的列表基于它们的访问控制列表上的用户以及在CRUD观点填充分工和部门选择列表优雅的方式?
  2. 有没有更好的方法来建立此访问控制列表?
+1

你是否已经有了一个“不雅”的解决方案,可以改善?对于公司,部门和部门而言,可能出现的'空'案件很难解决问题,甚至更多的是一种“优雅”的解决方案,不会有冗长的案件延期序列。如果没有'null'sa查询可能是:'var query = from c in context.Contents join in a context.AccessControls on new {c.CompanyId,c.DivisionId,c.DepartmentId} equals new {a.CompanyId,a。 DivisionId,a.DepartmentId}其中a.UserProfile.UserId == givenUserId选择c;'但我未能扩展这个以覆盖'null's。 – Slauma 2013-03-02 14:47:25

+0

关于您的部门/部门选择清单,您能否详细说明您对CRUD视图的设想? (即你想做什么可以做一个视图) – 2013-03-02 18:19:09

+0

谢谢你的答案。如果用户A有两个访问控制对象。一个可以访问分区1,会计和另一个可访问分区1,财务部门,然后在创建,更新或删除时选择列表将为分部提供分区1,为部门选择列表提供会计和财务部。如果用户对所有部门(即部门为NULL)和部门销售部门都有一个访问控制对象,则选择清单将包含所有定义的部门,并且仅包含销售部门。 – tomc 2013-03-02 23:27:44

回答

0

我不认为这解决您的所有问题,但我认为一个仓库,看起来是这样的:

public class accessRepository 
{ 
    accessContext context = new accessContext(); 

    public IQueryable<Content> GetAccessibleContentFor(int userId) 
    { 
     var up = context.UserProfiles.Single(u => u.UserId == userId); 
     var companyId = up.CompanyId; 

     return from c in context.Content 
       where c.CompanyId == companyId 
       && (up.AccessControl.Any(
        a=> 
         a.CompanyId == c.CompanyId && 
         a.DivisionId == c.DivisionId && 
         a.DepartmentId == c.DepartmentId) 
       || up.AccessControl.Any(
        a=>a.CompanyId == c.CompanyId && 
         a.DivisionId == c.DivisionId && 
         a.DepartmentId == null) 
       || up.AccessControl.Any(
        a=> 
         a.CompanyId == c.CompanyId && 
         a.DivisionId == null) 
       select c; 
    } 
} 

将使你回来是访问的内容,如果:

  1. 该内容属于用户的公司。
  2. 用户可访问内容的公司,部门和部门
  3. 或者用户可以访问的公司和部门的内容(全系)
  4. 或者用户能够对公司访问内容(各部门) [各部门,假设在这种情况下。]
+0

我有一些疑问,这将工作,因为你在一个单一的查询(“a.XXX”是内存中的值和'c.XXX'是数据库值)混合LINQ到实体与LINQ到对象,这将可能会在运行时抛出异常。 – Slauma 2013-03-02 18:53:42

+0

我不确定您的评论是否有效。这里的所有东西都是IQueryable,因此应该能够一直生成SQL直至实际的请求。我一直在构建一个测试实现,并且到目前为止它看起来会起作用。当然,我喜欢戴维斯布罗萨尔的建议甚至比我的解决方案更好。 – 2013-03-03 13:27:05

+0

'up.AccessControl'不是'IQueryable ',它只是内存中由延迟加载填充的本地集合。我会期望臭名昭着的“*无法创建恒定价值bla bla ... *”异常(http://stackoverflow.com/questions/7220867/unable-to-create-a-constant-value-of-type-type -only原语类型 - 例如-AS)。但也许我错了... – Slauma 2013-03-03 21:14:08

0

你应该寻找到一个政策和基于属性的解决方案,它独立于您的应用程序,在那里你可以写授权策略,如

用户可以访问仓库中的内容如果content.department == user.department & & content.company == user.company。

XACML听起来像是一个完美的模型。我写了这个演示,我根据购买者,采购订单的数量,位置和状态对采购订单进行了访问控制。我不需要更改应用程序代码,因为我在外部使用XACML。