[英]Store User Settings in ASP.NET Core Identity AspNetUsers Table or Not
[英]How to conditionally map multiple models to one table (AspNetUsers) in ASP.NET Core Identity?
我正在 ASP.NET Core MVC 中创建学习评估 web 应用程序。 我计划拥有两个独立的数据库:一个用于使用 Identity Framework 的用户,另一个用于使用 Dapper 的数据。 但是,我的模型与我的用户( Instructor
、 Student
)有关系。 这是我绘制的显示关系的实体关系图:
例如,我必须为每个Student
实例包含一个Course
导航属性。 同样, TestInstance
包含Instructor
和Student
的导航属性,明确区分了两个用户类。 我还需要另一个名为Administrator
的用户 class :
用户 Class | 责任 |
---|---|
Student |
参加考试 |
Instructor |
创建和安排测试 |
Administrator |
管理教师和学生的帐户和课程。 拥有导师的所有特权 |
我知道可以通过从IdentityUser
派生来在 Identity 中创建自定义属性,但我需要维护三个不同的用户类,而 Identity 只提供一个名为AspNetUsers
的表。 我不想在我的域 model 中直接使用 Identity 中的表。 事实上,如果 Identity 可以拥有自己的独立数据库,那就太好了。 管理员将是创建和管理教师和学生帐户的人。
我的问题是:
有什么方法可以创建三个模型/实体Student
、 Instructor
和Adminstrator
作为我的域 model 的一部分,然后让它们都使用 Identity 的AspNetUsers
表中的 ID? 他们的角色信息可以存储为声明或 Identity 提供的AspNetUserRoles
表中。
然后我可以使用 Identity 添加策略来实现访问控制。
我希望这不是设计缺陷。 如果我的项目处于初始阶段,我仍然可以重新考虑设计。
例如,您可以将 TPT 与 EF Core 5 一起使用,此项目将 TPT 与 ASP.NET Core Identity 集成。
https://github.com/ArminShoeibi/SchoolManagementSystem
public class ApplicationUser : IdentityUser<Guid>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string NationalCode { get; set; }
public DateTime BirthDate { get; set; }
public Gender Gender { get; set; }
}
public class Student : ApplicationUser
{
public string FatherName { get; set; }
public string PlaceOfBirth { get; set; }
public string Address { get; set; }
public string HomePhoneNumber { get; set; }
}
public class Teacher : ApplicationUser
{
public string FieldOfStudy { get; set; }
public AcademicDegree AcademicDegree{ get; set; }
public int YearsOfExperience { get; set; }
}
public class SchoolMgmtContext : IdentityDbContext<ApplicationUser,ApplicationRole,Guid>
{
public SchoolMgmtContext(DbContextOptions<SchoolMgmtContext> dbContextOptions)
:base(dbContextOptions)
{
}
public DbSet<Teacher> Teachers { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>().ToTable("Users");
builder.Entity<ApplicationRole>().ToTable("Roles");
builder.Entity<Student>().ToTable("Students");
builder.Entity<Teacher>().ToTable("Teachers");
}
}
讲师也可以是管理员吗? 如何处理这种多角色授权?
也许这在这种情况下无关紧要,但我喜欢在随后因“新见解”而面临用户的更改请求之前考虑此类质量/架构问题。
就个人而言,我会考虑创建一种Role
表,其中包含三个角色。 使用单独的UserRole
表,您可以在用户及其角色之间创建多对多关系。 因此,我将在这里使用一种组合,而不是使用继承/派生。
我认为您当前使用AspNetUsers
的逻辑将保持不变。 也许您可以使用 Identity 添加策略,以基于这两个额外的角色相关表来实现访问控制?
编辑
您还可以进一步 go 并创建一个附加的Right
表,其中包含单独的用户权限,例如参加测试、创建测试、安排测试、管理帐户等。您可以创建一个单独的RoleRight
表以将这些权限分配给所需的角色.
这将使您的角色更具动态性,甚至可能由用户配置。 (当然,在后一种情况下,只有用户有权创建和管理角色。)
然后在您的代码中,您可以检查用户是否具有分配的特定权限(通过其角色)。 例如,在负责创建测试的代码中,您可能实际上想要检查用户是否有权创建测试,而不是明确检查用户是否是讲师。
无论如何,这只是我对这个问题的 50 美分。 希望能帮助到你。
我认为您可以通过创建一个用户表来轻松解决这个问题,该表是所有可能访问系统的系统用户(学生、教师、管理员)的清单,其中包含 ID、名称、email 地址等共享属性。 (一定要加盐你存储的任何密码!)
然后,您有两个前进的选择:您可以使用此处的多表方法 go ,只需让每个“角色表”通过 userId 连接到用户表并将唯一属性存储到该角色:在您的示例中,学生表可能只是一个课程 ID 和一个用户 ID。 这使您可以在发现每个角色时使用其他属性自定义它们。
或者,您可以将角色组合到一个表中,但除非您做一些工作来抽象独特的属性,否则您最终可能会得到一个非常宽的表,其中包含许多不适用于每个角色的属性的空白值. 不要这样做。 一开始很容易,但是随着你的应用程序的增长,这个表会变得一团糟。
只需添加一个“用户”表,您就可以通过对现有架构的最小更改来进行改进。
另一个注意事项:学生和课程之间是一对一的关系。 我可能是错的,但您可能希望这是一对多的,因为大多数学生一次会学习多门课程。 你的旅费可能会改变。
因为紧密结合
我想提出紧密集成的存在是核心问题。 如果您的设计没有创建紧密集成,那么问题就会消失。 您可以确定您的设计的集成程度。
关注点分离
有很好的 arguments 和实际用例,用于为身份维护一个单独的数据库,为应用程序本身维护一个数据库。 我最近开发和部署了这样一个应用程序,我对结果非常满意。
第一个原因是“当另一个应用程序添加到组合中时会发生什么?”。 在野外,身份服务往往是孤立的:Azure AD、Google Cloud Identity、AWS 身份和访问管理等。除了固有的安全优势,身份服务将支持您现在和未来的所有应用程序,并且应该在一个特定的应用程序中不紧密耦合。
您的应用程序是基于 Web 的:当用户需要移动应用程序时会发生什么? 如果身份只能通过 web 应用程序访问,那么现在该怎么办? web 应用程序可能使用基于会话的身份验证,因此您需要重写所有这些以支持移动应用程序。 不会很漂亮
另一方面,假设您已经分离了服务。 此外,由于您的设计要求身份服务与平台无关,因此您实现了 JWT(JSON Web 令牌)支持身份验证。 在这种情况下,移动应用程序的身份验证将完全相同,没有任何变化
让我们把这个场景更进一步:你的应用程序的用户已经厌倦了点击“刷新”来查看他们的测试分数是否可用(拉)。 他们要求在考试成绩准备好(推送)时得到通知。
移动推送通知的实现与应用的核心功能无关; 它是以用户/平台为中心的功能。 如果您不相信这是真的,请考虑使用移动设备作为第二个因素的 2FA(双因素身份验证)。
身份从来都不是一个试验的好地方,而且可以说是你最不想犯错误的地方。 我相信您在身份解决方案中添加或调整的所有内容都可能增加攻击向量。 这是 KISS (Keep It Simple Stupid) 的教科书示例。
User
表是指Student
和Teacher
表; Identity
表是指AspNetUsers
。
正如您所说,如果表位于单个数据库中,它们将使用我们都知道和喜爱的标准“开箱即用”外键引用进行连接。
这是有趣的部分:我们可以自己动手:从根本上说,外键是非常基本的概念,这是一个 id。 用它来引用一些东西。 这是外键引用实现的唯一要求。
请记住: User
与Identity
不同。 系统通常会包含永远不会登录其系统的User
的数据。 此外,站点管理员很可能不是Teacher
或Student
。
对于标准用例,我的建议是首先创建User
实体,然后是Identity
。 然后使用您刚刚创建的Identity
的 ID 更新User
表中的可选列。
您想为每个Identity
添加角色或UserType
声明(Instructor、Student),以便知道您将在哪些User
表中找到User
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.