基于EF Core 3.1 DB First的.NET Core 3.1 WebApi集成Identity最新方案咨询
我最近帮几个朋友处理过类似的场景,针对.NET Core 3.1 WebApi(EF Core 3.1 数据库优先)集成ASP.NET Identity,现在有一套更顺畅的方案,比5年前的老帖子更省心,完全贴合DB First的流程:
1. 给现有数据库添加标准Identity表
不用手动写一堆SQL,我们可以借助Code First的迁移生成标准脚本,再同步到现有数据库:
- 临时新建一个.NET Core 3.1的空项目,安装两个NuGet包:
Microsoft.AspNetCore.Identity.EntityFrameworkCore和Microsoft.EntityFrameworkCore.Design - 新建一个临时的Identity DbContext:
public class TempIdentityDbContext : IdentityDbContext<IdentityUser> { public TempIdentityDbContext(DbContextOptions<TempIdentityDbContext> options) : base(options) {} }
- 在
appsettings.json里配置一个临时的连接字符串(随便找个测试库就行),然后打开Package Manager Console执行:Add-Migration InitialIdentity Script-Migration - 把生成的SQL脚本复制出来,执行到你的现有生产数据库里,这样就创建了AspNetUsers、AspNetRoles等全套标准Identity表。
2. 反向生成Identity实体到现有项目
回到你的DB First WebApi项目,用EF Core脚手架把刚添加的Identity表生成实体和DbContext代码:
- 执行以下Scaffold命令(记得替换成你的连接字符串和项目路径):
Scaffold-DbContext "Your_Connection_String" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables AspNetUsers, AspNetRoles, AspNetUserRoles, AspNetUserClaims, AspNetUserLogins, AspNetUserTokens, AspNetRoleClaims -ContextDir Data -Context YourExistingDbContext -Force
这里的-Force会更新你现有的DbContext,自动添加Identity表对应的DbSet,同时在Models目录生成所有Identity实体类(比如AspNetUser、AspNetRole)。
3. 修改现有DbContext继承IdentityDbContext
你的现有DbContext之前应该是继承DbContext,现在要改成继承IdentityDbContext<AspNetUser>(这里的AspNetUser就是刚生成的实体类):
public class YourExistingDbContext : IdentityDbContext<AspNetUser> { // 保留你原来的构造函数和业务表DbSet public YourExistingDbContext(DbContextOptions<YourExistingDbContext> options) : base(options) {} // 脚手架已经自动添加了Identity相关DbSet,比如: public virtual DbSet<AspNetRole> AspNetRoles { get; set; } public virtual DbSet<AspNetUser> AspNetUsers { get; set; } // 其他Identity表的DbSet... }
如果你的AspNetUsers表有自定义字段(比如昵称、头像地址),生成的AspNetUser实体已经包含这些字段,直接用就行。
4. 在Startup里配置Identity服务
打开Startup.cs,在ConfigureServices里注册Identity服务:
services.AddIdentity<AspNetUser, AspNetRole>(options => { // 按需配置规则,比如密码复杂度、账户锁定策略 options.Password.RequireDigit = true; options.Password.RequiredLength = 6; options.Lockout.MaxFailedAccessAttempts = 5; }) .AddEntityFrameworkStores<YourExistingDbContext>() .AddDefaultTokenProviders();
然后在Configure方法里,把认证中间件加到路由之前:
app.UseAuthentication(); // 先认证 app.UseAuthorization(); // 再授权 app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
5. 可选:优化与兼容处理
- 如果原来项目有自己的用户表,需要先做数据迁移:把原有用户数据导入AspNetUsers表,然后删除旧用户表,调整业务代码改用AspNetUser实体。
- 要是不需要角色功能,可以只生成AspNetUsers、AspNetUserClaims等必要表,DbContext继承
IdentityDbContext<AspNetUser>即可(不用加AspNetRole泛型参数)。 - 嫌实体类名带AspNet前缀麻烦?可以手动改类名(比如AspNetUser改成User),然后在DbContext里用
EntityTypeBuilder映射到数据库表:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<User>().ToTable("AspNetUsers"); // 其他实体同理 }
为什么这个方案更靠谱?
5年前的老方案大多是手动创建Identity实体、写映射关系,很容易出错。现在这个方法借助EF Core的脚手架和迁移工具,既严格遵循DB First的流程,又保证了Identity表结构的标准性,不用自己写重复代码,兼容性也更好。
内容的提问来源于stack exchange,提问作者user728801

