ASP.NET身份用户和多站点中的角色

时间:2014-01-16 15:27:35

标签: asp.net-mvc roles asp.net-identity

我正在尝试在ASP.NET MVC应用程序中创建权限系统。我一直在学习最新的身份框架 - 这是我的要求:

  1. 每组功能的一组分层角色。因此,例如,可能存在以下角色:
    • 继承
    • 阅读器
    • 编辑
    • 管理器
    • 管理员
  2. 每个用户将拥有每个模块的其中一个角色(例如,活动,页面等)
  3. 用户可以是安全组的成员。可以直接为每个安全组分配角色,然后该组中的所有用户(未明确分配该权限的用户)将继承该角色。
  4. 多租户网站:每个用户都有一组他们所属的网站。在每个站点的上下文中,它们具有一组完整的权限,可由站点管理员分配。
  5. 通过扩展ASP.NET身份,我可以完成所有这些吗?或者我应该从头开始构建一些定制的东西吗?

2 个答案:

答案 0 :(得分:7)

实施您自己的身份验证系统的10,000个中有9,999次是错误的方法。任何事情都比这更容易,而正确是一件看似困难的事情。 ASP.NET Identity实际上是可定制的,因为它是专门为此目的而创建的。您可能需要做很多工作才能完全引导您的自定义需求,但使用ASP.NET标识几乎肯定会更快更安全。

<强>更新

UserManager的构造函数采用IUserStore的实现。在使用Entity Framework时,您通常只需提供它Microsoft.AspNet.Identity.EntityFramework.UserStore,但这是您可扩展性的关键点。因此,您可以简单地继承UserStore,然后覆盖类似GetRolesAsync的内容,以执行您需要实现的任何自定义角色逻辑。那么你只需要提供UserManager你的子类。

答案 1 :(得分:7)

在ASP.NET成员资格的1.0版中,IRole接口必须具有string主键。但是,在2014年3月发布的2.0版中,他们添加了IRole<TKey>,允许您指定角色的主键,只要TKey实现IEquatable<TKey>

也就是说,开箱即用的MVC集成点仍然取决于单个字符串ID的角色。因此,如果您要通过Authorize这样的属性进行授权,那么您可能需要编写自己的自定义授权属性。

实现分层角色的一种方法是在应用程序中而不是在模型中处理它。我假设按层次结构,您的意思是管理员拥有管理员的所有权限,管理员具有与编辑者相同的权限,依此类推。您可以通过将用户添加到多个角色来实现此目的,而不必遍历建模的角色层次结构。类似于db触发器的东西可以做到这一点,但您也可以将其建模为代码中的业务规则。然后,如果您将页面限制为编辑器,管理员&amp;经理们也可以访问它。

另一种方法是仅为多个角色授权某些操作:

[Authorize(Roles = "Administrator, Manager, Editor")]
public ActionResult Edit()

[Authorize(Roles = "Administrator, Manager")]
public ActionResult Manage()

[Authorize(Roles = "Administrator")]
public ActionResult Admin()

我不同意你想要在复合键上识别角色。如果要使用Authorize属性保护MVC操作,则角色的ID必须是常量值,如字符串文字,int或Enum值等。如果您在多个属性上键入了角色,则该数字您需要在属性上设置的属性乘以ID的每个组件中的值的数量。您将拥有Manager / SiteA,Manager / SiteB等。

相反,听起来像添加属性来追踪角色中的用户(多对多关系中的中间表)可能是一个好主意。要做到这一点,您将无法像@Chris Pratt建议的那样简单地覆盖和扩展UserManager类中的方法。但这并不意味着你必须把洗澡水扔掉。您仍然可以使用Microsoft.AspNet.Identity进行身份验证,只需编写自己的角色管理方法,将其扩充为另外一个参数:

AddToRoleAsync(TUser user, string roleName, string siteId);

public class Role : IRole<int>
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<UserInRole> Authorizes { get; set; }
}
public class UserInRole
{
    public int RoleId { get; set; } // part of composite primary key
    public int UserId { get; set; } // part of composite primary key
    public string SiteId { get; set; } // part of composite primary key
    public virtual Role Role { get; set; }
    public virtual User User { get; set; }

}
public class User : IUser<int>
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<UserInRole> Authorized { get; set; }
}

鉴于上述情况,请说明您的网址如下:

/sites/site-a/admin
/sites/site-b/manage
/sites/site-c/edit
/sites/{siteId}/do

...您可以编写一个自定义授权属性来检查URL,并根据属性中的角色名称和URL中的siteId对主体进行授权。要从属性访问数据库,如果您正在使用IoC for EntityFramework,您可以使用属性注入DbContext的实例(或者包装它的任何接口)。