You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET Core 6清洁架构中迁移Identity至Persistence项目

分步迁移Identity到MyProject.Persistence并隔离EF Core

1. 配置MyProject.Persistence依赖

给MyProject.Persistence安装以下NuGet包:

  • Microsoft.AspNetCore.Identity.EntityFrameworkCore(Identity与EF Core集成核心包)
  • Microsoft.EntityFrameworkCore.SqlServer(根据你的数据库更换对应提供商,比如MySQL用Pomelo.EntityFrameworkCore.MySql)
  • Microsoft.EntityFrameworkCore.Tools(用于EF Core迁移操作)

确保MyProject.Persistence已引用MyProject.Shared.Models(如果需要共享自定义Identity实体或DTO)

2. 迁移Identity相关文件

  • 从MyProject.UI.Web的Data文件夹,复制ApplicationDbContext.cs和Migrations目录到MyProject.Persistence下的Data子目录(没有就新建)
  • 修改复制后文件的命名空间:将MyProject.UI.Web.Data替换为MyProject.Persistence.Data
  • 删除MyProject.UI.Web中的Data文件夹

3. 调整ApplicationDbContext

在MyProject.Persistence的ApplicationDbContext.cs中,确保正确继承并配置:

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace MyProject.Persistence.Data;

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    // 如果有自定义Identity实体(如ApplicationUser),替换泛型参数:
    // public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
}

4. 封装Persistence层服务注册

在MyProject.Persistence中新建PersistenceServiceExtensions.cs,统一注册DbContext和Identity服务:

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using MyProject.Persistence.Data;

namespace MyProject.Persistence;

public static class PersistenceServiceExtensions
{
    public static IServiceCollection AddPersistenceServices(this IServiceCollection services, string connectionString)
    {
        // 注册DbContext
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(connectionString));

        // 注册Identity核心服务,绑定EF Core存储
        services.AddIdentityCore<IdentityUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        // 若使用自定义User,替换IdentityUser为你的实体类
        // services.AddIdentityCore<ApplicationUser>()

        return services;
    }
}

5. 清理并配置MyProject.UI.Web

  • 卸载MyProject.UI.Web中所有EF Core相关NuGet包(包括Microsoft.EntityFrameworkCore.SqlServer、Microsoft.AspNetCore.Identity.EntityFrameworkCore等)
  • 在Program.cs中通过Persistence扩展方法注册服务,替换原有的Identity/EF Core配置:
using MyProject.Persistence;

var builder = WebApplication.CreateBuilder(args);

// 注册Persistence层服务,传入连接字符串
builder.Services.AddPersistenceServices(builder.Configuration.GetConnectionString("DefaultConnection"));

// 添加MVC控制器和视图支持
builder.Services.AddControllersWithViews();

// 配置Identity认证方案
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = IdentityConstants.ApplicationScheme;
    options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies();

var app = builder.Build();

// 保留原有中间件配置(静态文件、路由、认证授权等)
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

6. 修复迁移命令执行

  • Package Manager Console:设置默认项目为MyProject.Persistence,执行迁移时指定启动项目:
Add-Migration [迁移名称] -StartupProject MyProject.UI.Web
Update-Database -StartupProject MyProject.UI.Web
  • .NET CLI:
dotnet ef migrations add [迁移名称] --project MyProject.Persistence --startup-project MyProject.UI.Web
dotnet ef database update --project MyProject.Persistence --startup-project MyProject.UI.Web

7. 适配登录业务流程

按照你的设计(UI→服务→API),需要通过业务服务层封装Identity逻辑,避免UI直接依赖Persistence:

  1. 新建MyProject.Services项目,引用MyProject.Persistence和MyProject.Shared.Models
  2. 在Services中实现认证服务:
using Microsoft.AspNetCore.Identity;

namespace MyProject.Services;

public class AuthService
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly SignInManager<IdentityUser> _signInManager;

    public AuthService(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }

    public async Task<SignInResult> LoginAsync(string email, string password, bool rememberMe)
    {
        var user = await _userManager.FindByEmailAsync(email);
        if (user == null) return SignInResult.Failed();

        return await _signInManager.PasswordSignInAsync(user, password, rememberMe, lockoutOnFailure: false);
    }
}
  1. 在Services中添加服务注册扩展:
using Microsoft.Extensions.DependencyInjection;

namespace MyProject.Services;

public static class ServiceExtensions
{
    public static IServiceCollection AddBusinessServices(this IServiceCollection services)
    {
        services.AddScoped<AuthService>();
        return services;
    }
}
  1. 在UI.Web的Program.cs中注册业务服务:
builder.Services.AddBusinessServices();
  1. UI控制器注入AuthService实现登录:
public class AccountController : Controller
{
    private readonly AuthService _authService;

    public AccountController(AuthService authService)
    {
        _authService = authService;
    }

    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (!ModelState.IsValid) return View(model);

        var result = await _authService.LoginAsync(model.Email, model.Password, model.RememberMe);
        if (result.Succeeded) return RedirectToAction("Index", "Home");

        ModelState.AddModelError(string.Empty, "登录失败,请检查邮箱或密码");
        return View(model);
    }
}

关键注意事项

  • 依赖链必须清晰:UI.Web → Services → Persistence → Shared.Models
  • 迁移文件移动后,务必确认命名空间与项目结构匹配,避免编译错误
  • 如需自定义Identity规则(如密码复杂度),可在Persistence的AddPersistenceServices中通过AddIdentityCore链式配置(比如.AddPasswordValidator<CustomPasswordValidator>())

内容的提问来源于stack exchange,提问作者micex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:00:08