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

如何在ASP.NET Core Web API Identity用户注册时添加额外字段

解决方案

1. 修正Identity映射与DbContext配置

你当前代码里存在两个问题:一是MapIdentityApi<IdentityUser>使用了默认用户类,和自定义的UserEntity不匹配;二是重复添加了DbContext实例。先修正这两处:

// 移除内存数据库的DbContext配置,保留PostgreSQL的配置
builder.Services.AddDbContext<QuiltDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

// 将MapIdentityApi的泛型参数改为自定义的UserEntity
app.MapGroup("/my-identity-api").MapIdentityApi<UserEntity>();

2. 创建注册请求DTO

定义包含所有必填字段的DTO,用于接收前端的注册参数:

using System.ComponentModel.DataAnnotations;

namespace Quilt.Models.DTOs
{
    public class RegisterRequest
    {
        [Required]
        [EmailAddress]
        public string Email { get; set; }

        [Required]
        [MinLength(6)]
        public string Password { get; set; }

        [Required]
        public string FirstName { get; set; }

        [Required]
        public string LastName { get; set; }

        [Required]
        [DataType(DataType.Date)]
        public DateTime Birthday { get; set; }

        public string? Avatar { get; set; }

        [Required]
        public string Gender { get; set; }
    }
}

3. 自定义注册端点

默认的MapIdentityApi提供的注册接口只支持邮箱和密码,因此需要自定义注册端点,借助Identity的UserManager完成用户创建与额外字段赋值:

app.MapPost("/my-identity-api/register", async (
    [FromBody] RegisterRequest request,
    UserManager<UserEntity> userManager,
    SignInManager<UserEntity> signInManager) =>
{
    // 验证DTO参数合法性
    var validationResults = new List<ValidationResult>();
    if (!Validator.TryValidateObject(request, new ValidationContext(request), validationResults, validateAllProperties: true))
    {
        return Results.ValidationProblem(validationResults.ToDictionary(
            v => v.MemberNames.FirstOrDefault() ?? string.Empty,
            v => new[] { v.ErrorMessage }));
    }

    // 实例化自定义用户类并赋值额外字段
    var user = new UserEntity
    {
        UserName = request.Email,
        Email = request.Email,
        FirstName = request.FirstName,
        LastName = request.LastName,
        Birthday = request.Birthday,
        Avatar = request.Avatar,
        Gender = request.Gender
    };

    // 调用Identity核心方法创建用户(自动处理密码哈希)
    var createResult = await userManager.CreateAsync(user, request.Password);

    if (!createResult.Succeeded)
    {
        return Results.BadRequest(createResult.Errors.Select(e => new { e.Code, e.Description }));
    }

    // 注册成功后直接生成Bearer Token(可选,若不需要可跳过此段)
    var accessToken = await signInManager.GenerateUserTokenAsync(user, TokenOptions.DefaultProvider, "Bearer");
    return Results.Ok(new { AccessToken = accessToken });
})
.WithName("CustomRegister")
.WithOpenApi();

4. 完整修正后的Program.cs示例

using System.Security.Claims;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Quilt.DataAccess.Data;
using Quilt.Models.User;

var builder = WebApplication.CreateBuilder(args);

// 配置DbContext
builder.Services.AddDbContext<QuiltDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

// 配置认证与授权
builder.Services.AddAuthentication().AddBearerToken(IdentityConstants.BearerScheme);
builder.Services.AddAuthorizationBuilder();

// 配置自定义Identity用户
builder.Services.AddIdentityCore<UserEntity>()
    .AddEntityFrameworkStores<QuiltDbContext>()
    .AddApiEndpoints()
    .AddDefaultTokenProviders();

// 配置Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// 映射Identity基础接口(登录、token刷新等)
app.MapGroup("/my-identity-api").MapIdentityApi<UserEntity>();

// 自定义注册接口
app.MapPost("/my-identity-api/register", async (
    [FromBody] RegisterRequest request,
    UserManager<UserEntity> userManager,
    SignInManager<UserEntity> signInManager) =>
{
    var validationResults = new List<ValidationResult>();
    if (!Validator.TryValidateObject(request, new ValidationContext(request), validationResults, validateAllProperties: true))
    {
        return Results.ValidationProblem(validationResults.ToDictionary(
            v => v.MemberNames.FirstOrDefault() ?? string.Empty,
            v => new[] { v.ErrorMessage }));
    }

    var user = new UserEntity
    {
        UserName = request.Email,
        Email = request.Email,
        FirstName = request.FirstName,
        LastName = request.LastName,
        Birthday = request.Birthday,
        Avatar = request.Avatar,
        Gender = request.Gender
    };

    var createResult = await userManager.CreateAsync(user, request.Password);

    if (!createResult.Succeeded)
    {
        return Results.BadRequest(createResult.Errors.Select(e => new { e.Code, e.Description }));
    }

    var accessToken = await signInManager.GenerateUserTokenAsync(user, TokenOptions.DefaultProvider, "Bearer");
    return Results.Ok(new { AccessToken = accessToken });
})
.WithName("CustomRegister")
.WithOpenApi();

// 测试授权接口
app.MapGet("/", (ClaimsPrincipal user) => $"Hello {user.Identity!.Name}").RequireAuthorization();

// 开发环境启用Swagger
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.Run();

// 注册请求DTO定义(可单独放到类文件中)
public class RegisterRequest
{
    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    [MinLength(6)]
    public string Password { get; set; }

    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    [Required]
    [DataType(DataType.Date)]
    public DateTime Birthday { get; set; }

    public string? Avatar { get; set; }

    [Required]
    public string Gender { get; set; }
}

核心说明

  • 全程复用ASP.NET Core Identity的核心组件(UserManager、SignInManager),保证认证逻辑的安全性与规范性;
  • 自定义DTO实现前端参数的接收与验证,避免直接暴露实体类;
  • 可选择在注册后直接返回Bearer Token,简化前端流程,也可仅返回注册成功提示,让用户后续走登录流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 11:53:20