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

ASP.NET 4.5.2 MVC迁移至Core6:Identity转JWT并保留用户密码

迁移至ASP.NET Core 6 + 自定义用户+JWT并保留原密码有效性

1. 复刻原用户表结构到Core项目

先在ASP.NET Core 6项目中创建自定义用户实体,对齐原数据库Identity用户表的核心字段:

public class AppUser
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public string PasswordHash { get; set; }
    public string Email { get; set; }
    // 原表中的其他自定义字段直接复制
}

通过EF Core配置DbContext,映射到原数据库的用户表(默认表名AspNetUsers):

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<AppUser> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AppUser>().ToTable("AspNetUsers");
        modelBuilder.Entity<AppUser>().HasKey(u => u.Id);
        // 按需配置字段长度、索引等
    }
}

2. 实现兼容原Identity的密码验证

ASP.NET Core的PasswordHasher<AppUser>原生支持验证ASP.NET Identity 2.x(对应.NET 4.5.2)生成的密码哈希,无需手动实现旧算法。封装用户服务类处理验证逻辑:

public class UserService
{
    private readonly AppDbContext _dbContext;
    private readonly PasswordHasher<AppUser> _passwordHasher;

    public UserService(AppDbContext dbContext)
    {
        _dbContext = dbContext;
        _passwordHasher = new PasswordHasher<AppUser>();
    }

    public async Task<AppUser> ValidateUserAsync(string userName, string password)
    {
        var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.UserName == userName);
        if (user == null) return null;

        // 验证旧哈希,支持自动识别格式
        var verifyResult = _passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password);
        return verifyResult is PasswordVerificationResult.Success or PasswordVerificationResult.SuccessRehashNeeded 
            ? user 
            : null;
    }

    // 可选:用户登录时自动将旧哈希升级为Core的新格式
    public async Task UpgradePasswordHashAsync(AppUser user, string password)
    {
        var result = _passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password);
        if (result == PasswordVerificationResult.SuccessRehashNeeded)
        {
            user.PasswordHash = _passwordHasher.HashPassword(user, password);
            _dbContext.Users.Update(user);
            await _dbContext.SaveChangesAsync();
        }
    }
}

3. 配置JWT认证服务

在Program.cs中注册JWT认证相关服务:

var builder = WebApplication.CreateBuilder(args);

// 注册DbContext,使用原数据库连接字符串
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

// 注册用户服务
builder.Services.AddScoped<UserService>();

// 配置JWT认证
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"]))
        };
    });

builder.Services.AddControllersWithViews();

var app = builder.Build();

// 中间件顺序:认证在前,授权在后
app.UseAuthentication();
app.UseAuthorization();

// 其他中间件配置(静态文件、路由等)
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

在appsettings.json中添加JWT配置项:

{
  "ConnectionStrings": {
    "DefaultConnection": "原数据库连接字符串"
  },
  "Jwt": {
    "Issuer": "你的服务标识",
    "Audience": "你的客户端标识",
    "SecretKey": "至少16位的安全密钥(如your_secure_jwt_secret_123)",
    "ExpiresInMinutes": 60
  }
}

4. 实现登录接口生成JWT令牌

创建认证控制器处理登录请求:

[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
    private readonly UserService _userService;
    private readonly IConfiguration _config;

    public AuthController(UserService userService, IConfiguration config)
    {
        _userService = userService;
        _config = config;
    }

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginRequest request)
    {
        var user = await _userService.ValidateUserAsync(request.UserName, request.Password);
        if (user == null) return Unauthorized("用户名或密码错误");

        // 可选:升级密码哈希格式
        await _userService.UpgradePasswordHashAsync(user, request.Password);

        // 生成JWT令牌
        var token = GenerateJwtToken(user);
        return Ok(new { Token = token });
    }

    private string GenerateJwtToken(AppUser user)
    {
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.UserName),
            new Claim(ClaimTypes.Email, user.Email)
            // 添加自定义Claim(如角色、权限)
        };

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:SecretKey"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.Now.AddMinutes(Convert.ToDouble(_config["Jwt:ExpiresInMinutes"])),
            signingCredentials: creds);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

public class LoginRequest
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

5. 替换原有身份验证逻辑

将原项目中依赖Identity的用户信息获取逻辑,改为从JWT Claims中提取:

public class HomeController : Controller
{
    [Authorize] // 需要授权的Action添加该特性
    public IActionResult SecurePage()
    {
        // 从Claims获取当前用户信息
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        var userName = User.FindFirstValue(ClaimTypes.Name);
        // 业务逻辑处理
        return View();
    }
}

关键注意事项

  • 确保原数据库PasswordHash字段完整迁移,无截断或修改
  • 若原项目使用了自定义密码哈希器,需在Core项目中复刻相同的验证逻辑(默认PBKDF2格式无需额外处理)
  • 测试阶段用原数据库的真实账号验证密码有效性
  • 自动升级哈希格式可提升后续密码存储的安全性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 21:18:20