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

ASP.NET 8 Web API如何编辑Identity默认端点(不含MVC布局文件)

ASP.NET 8 Web API 自定义Identity登录端点的实用方案

方案一:手动编写API端点,复用Identity核心登录逻辑

既然你不想从头写复杂的登录验证(密码校验、账户锁定、双因素验证等),可以直接注入Identity的核心服务(SignInManager<TUser>、UserManager<TUser>),自定义InputModel后调用官方封装好的登录逻辑,完全不需要依赖MVC相关文件。

步骤示例:

  1. 定义自定义登录输入模型
public class CustomLoginInputModel
{
    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    // 按需添加你的扩展字段
    public bool RememberMe { get; set; } = false;
    public string? ExtraUserInfo { get; set; }
}
  1. 编写API控制器的登录方法
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly UserManager<ApplicationUser> _userManager;

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

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] CustomLoginInputModel model)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        // 根据邮箱查询用户(用用户名登录就换FindByNameAsync)
        var user = await _userManager.FindByEmailAsync(model.Email);
        if (user == null)
            return Unauthorized("无效的登录凭据");

        // 调用Identity核心登录逻辑,自动处理密码验证、账户锁定等
        var signInResult = await _signInManager.CheckPasswordSignInAsync(user, model.Password, lockoutOnFailure: true);

        if (signInResult.Succeeded)
        {
            // 处理你的扩展字段逻辑,比如根据ExtraUserInfo更新用户属性
            if (!string.IsNullOrEmpty(model.ExtraUserInfo))
            {
                user.ExtraField = model.ExtraUserInfo;
                await _userManager.UpdateAsync(user);
            }

            // 登录成功,返回JWT或自定义响应(根据你的API需求)
            await _signInManager.SignInAsync(user, model.RememberMe);
            return Ok(new { UserId = user.Id, Message = "登录成功" });
        }
        else if (signInResult.IsLockedOut)
            return Unauthorized("账户已锁定,请10分钟后重试");
        else if (signInResult.IsNotAllowed)
            return Unauthorized("账户未激活,请先验证邮箱");
        else
            return Unauthorized("密码错误");
    }
}

方案二:生成脚手架后清理冗余文件,保留核心逻辑

如果已经通过脚手架生成了登录相关文件,可以直接删除所有.cshtml、布局文件,只保留Login.cshtml.cs中的逻辑代码,将其改造为可复用的业务逻辑类,而非MVC页面模型。

改造示例:

  1. 删除所有.cshtml文件,将Login.cshtml.cs修改为独立逻辑类:
public class LoginService
{
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly ILogger<LoginService> _logger;

    public LoginService(SignInManager<ApplicationUser> signInManager, ILogger<LoginService> logger)
    {
        _signInManager = signInManager;
        _logger = logger;
    }

    // 自定义InputModel,添加扩展字段
    public class LoginInputModel
    {
        [Required]
        [EmailAddress]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }

        public bool RememberMe { get; set; }
        public string? CustomField { get; set; }
    }

    public async Task<SignInResult> ExecuteLoginAsync(LoginInputModel model)
    {
        // 复用脚手架生成的核心登录逻辑
        var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: true);
        
        if (result.Succeeded)
        {
            _logger.LogInformation("用户登录成功");
            // 在这里处理你的扩展字段业务
        }
        return result;
    }
}
  1. 在API控制器中注入这个服务使用:
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
    private readonly LoginService _loginService;

    public AuthController(LoginService loginService)
    {
        _loginService = loginService;
    }

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginService.LoginInputModel model)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        var result = await _loginService.ExecuteLoginAsync(model);
        
        // 处理登录结果并返回响应
        if (result.Succeeded)
            return Ok("登录成功");
        // 其他情况的返回逻辑...
    }
}

方案三:使用Identity官方API端点,自定义扩展逻辑

ASP.NET 8支持直接启用Identity API端点,你可以通过自定义模型绑定或事件订阅来扩展登录逻辑,不需要手写完整端点。

配置示例:

  1. 在Program.cs中启用Identity API:
builder.Services.AddIdentityApiEndpoints<ApplicationUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

// 映射Identity API端点
app.MapIdentityApi<ApplicationUser>();
  1. 扩展登录请求模型:通过自定义绑定器将请求参数映射到包含扩展字段的模型,或者在登录事件中处理扩展逻辑:
// 订阅SignInManager的登录成功事件,处理扩展字段
builder.Services.AddScoped<SignInManager<ApplicationUser>>((sp) =>
{
    var signInManager = sp.GetRequiredService<SignInManager<ApplicationUser>>();
    signInManager.SignedIn += async (sender, args) =>
    {
        // args.User为当前登录用户,可直接操作扩展属性
        var customData = HttpContext.Request.Form["CustomField"].ToString();
        if (!string.IsNullOrEmpty(customData))
        {
            args.User.CustomField = customData;
            await sp.GetRequiredService<UserManager<ApplicationUser>>().UpdateAsync(args.User);
        }
    };
    return signInManager;
});

内容的提问来源于stack exchange,提问作者D.Alkhovik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:57:34