简体   繁体   English

这是实现强类型角色的良好数据模型吗?

[英]Is this a good data model to implement strongly-typed roles?

Yes, this has been asked before here and here . 是的, 这里这里都曾问过这个 问题 I'm curious as to whether the approach I'm considering is architecturally sound. 我对我正在考虑的方法在体系结构上是否合理感到好奇。

Let me start off by trying to describe what I'd like to be able to do with my object model: 首先,我尝试描述我希望对对象模型进行的处理:

class Person {
  ISet<Roles> Roles { get; set; }
}

class RoleDefinition {
  string Name { get; set; }
}

class RoleAssignment {
  RoleDefinition Definition { get; set; }
  Person Person { get; set; }
}

class UserRole : RoleAssignment {
  public virtual string Login { get; set; }
  public virtual string Password { get; set; }
}

With the intent being to be able to work with roles in the following manner: 旨在能够以以下方式使用角色:

// Find all "users" with a matching login
from user in userRolesRepository.FindAll(u => u.Login.StartsWith("abc")) 
select user.Person;

To do this, I'm considering the following data model 为此,我正在考虑以下数据模型

Person table (Id, Name)
RoleDefinition table (Id, Name)
RoleAssignment table (Id, DefId, PersonId)
UserRole table (RoleAssignmentId, Login, Password)
AdminRole table (RoleAssignmentId, ...)

I'll map UserRole and AdminRole as joined-sublass to RoleAssignment in NHibernate. 我将UserRole和AdminRole作为连接子映射到NHibernate中的RoleAssignment。

So, that's a 1:1 between Person and UserRole and AdminRole, a 1:1 between UserRole and RoleAssignment, and an n:1 between RoleAssignment and RoleDefinition. 因此,Person与UserRole和AdminRole之间为1:1,UserRole与RoleAssignment之间为1:1,RoleAssignment与RoleDefinition之间为n:1。

My question is this: Is this really a good model? 我的问题是:这真的是一个好模型吗?

Are there better ways to model this without losing the ability for each role to have strongly typed, queryable properties? 有没有更好的方法来对此建模,而又不会失去每个角色具有强类型可查询属性的能力? How well will it scale, considering I will be adding even more roles to the system as we move along? 考虑到随着我们的前进,我将在系统中添加更多角色,它将如何扩展?

At first glance, I think it's a bit odd for a single user to have multiple logins and passwords, one for each role, unless you will assume that a user always belongs to a single role. 乍一看,我认为单个用户拥有多个登录名和密码(每个角色一个)是有点奇怪的,除非您假设一个用户始终属于一个角色。 For example, if I had both belonged to roles named Accountant and Salesperson , such as might happen in a small business, it would seem by the definition above that I would have two RoleDefinition s and, as such, two logins and passwords. 例如,如果我都属于一个名为AccountantSalesperson角色(例如可能发生在小型企业中),则根据上面的定义,我似乎有两个RoleDefinition ,因此,两个登录名和密码。

Aside from that, in the past, I have mapped this similarly. 除此之外,在过去,我已经对此进行了类似的映射。 There is a User class, which is essentially a user profile and has properties such as string UserName , string HashedPassword , TimeZoneInfo TimeZonePreference , ISet<Role> Roles , etc, as well as a LogOn(string password) method. 有一个User类,它本质上是一个用户配置文件,并具有诸如string UserNamestring HashedPasswordTimeZoneInfo TimeZonePreferenceISet<Role> RolesISet<Role> Roles ,以及LogOn(string password)方法。

The LogOn() method of my User class does things like update the FailedLogonsCount property or TemporaryLockoutLiftedAtUtc property and so forth depending on whether or not hashing the passed in password succeeds against the one stored, or it returns a non-persisted object that implements IPrincipal , which is a standard .NET interface . 我的User类的LogOn()方法会执行诸如更新FailedLogonsCount属性或TemporaryLockoutLiftedAtUtc属性之类的操作,具体取决于是否对输入的密码进行散列处理是否成功对存储的密码进行哈希处理,或者是否返回实现IPrincipal的非持久对象这是标准的.NET接口

In this sense, I distinguish between the user's profile (the User class) and their authentication/authorization tokens (non-persisted classes that implement IPrincipal and IIdentity so that they can participate in the various [Authorize] and Thread.CurrentPrincipal schemes used throughout the .NET framework). 从这个意义上讲,我区分了用户的个人资料( User类)和它们的身份验证/授权令牌(实现IPrincipalIIdentity非持久类),以便他们可以参与整个应用程序中使用的各种[Authorize]Thread.CurrentPrincipal方案。 .NET框架)。 When the User instance creates the object that implements IPrincipal , it just passes a copy of the user's roles as an array of strings so that the IPrincipal 's IsInRole() method will work. User实例创建实现IPrincipal的对象时,它只是将用户角色的副本作为字符串数组传递,以便IPrincipalIsInRole()方法将起作用。

This means that my role names are essentially magic, well-known strings, in effect being a unique key in a Roles database table. 这意味着我的角色名称本质上是魔术的知名字符串,实际上是Roles数据库表中的唯一键。 But I don't think there's much of a way around that. 但是我认为这没有很多办法。 Indeed, my Role class looks like this: 确实,我的Role类如下所示:

class Role {
int? Identity { get; }   // database identifier that I never really look at
string RoleEnum { get; } // the "enumeration" that is 
                         //   the well-known string, used in IsInRole()
string RoleName { get; } // a human-friendly, perhaps 
                         //   localizable name of the role
}

I don't have separate subclasses for each role type. 对于每种角色类型,我没有单独的子类。 Do UserRole and AdminRole as classes really have separate behavior intrinsically? 作为类的UserRoleAdminRole是否真的在本质上具有单独的行为 I would submit that they are merely different data points of a generic Role class, so you don't need separate subclasses for each of them. 我认为它们只是通用Role类的不同数据点,因此您不需要为每个类分别使用单独的子类。

When you add a role to your system, you are either going to have re-compile the whole shebang with updated checks for that role (this is what I do, I don't expect to add a role frequently), or, if you really wanted to get fancy, the Role class could have a set of Permission objects or some such within them, and your code could just ask the role if role.AllowsUserToDoThis() and have all the permissions checking in one place. 当您向系统中添加角色时,您将需要使用该角色的更新检查重新编译整个shebang(这是我的工作,我不希望经常添加角色),或者,如果真的很想花哨, Role类可以包含一组Permission对象或其中的一些对象,并且您的代码可以只询问role.AllowsUserToDoThis()是否为role.AllowsUserToDoThis()并将所有权限检查在一个地方。 Configuring the role's set of Permissions would, therefore, allow you to edit fine-grained access control as the system is running, but you would lose the simplicity of the .NET-provided role-based security model. 因此,配置角色的权限集将允许您在系统运行时编辑细粒度的访问控制,但是您将失去.NET提供的基于角色的安全模型的简单性。

There is, as you might have guessed, a million ways to do it, but hopefully this is some helpful feedback. 您可能已经猜到有百万种方法可以这样做,但是希望这是一些有用的反馈。 Good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM