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

如何在React & ASP.NET Core项目中自定义Identity实现短信与邮件功能?

自定义ASP.NET Core Identity API以集成短信/邮件功能

当默认Identity API无法满足短信、邮件集成的自定义需求时,可通过以下步骤手动扩展实现:

1. 替换默认Identity API端点

默认AddIdentityApiEndpoints封装的固定接口无法直接修改,需手动接管:

  • 移除Program.cs中builder.Services.AddIdentityApiEndpoints<IdentityUser>()及app.MapIdentityApi<IdentityUser>()的调用。
  • 创建自定义认证控制器(如AccountController),自行实现注册、邮箱验证、密码重置等核心流程。

2. 实现邮件/短信发送服务

先定义统一发送接口,再完成具体发送逻辑:

定义发送接口

public interface IEmailSender
{
    Task SendEmailAsync(string email, string subject, string htmlMessage);
}

public interface ISmsSender
{
    Task SendSmsAsync(string phoneNumber, string message);
}

实现邮件发送服务(SMTP示例)

public class EmailSender : IEmailSender
{
    private readonly IConfiguration _configuration;

    public EmailSender(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public async Task SendEmailAsync(string email, string subject, string htmlMessage)
    {
        using var client = new SmtpClient(_configuration["Smtp:Host"], int.Parse(_configuration["Smtp:Port"]))
        {
            Credentials = new NetworkCredential(_configuration["Smtp:Username"], _configuration["Smtp:Password"]),
            EnableSsl = bool.Parse(_configuration["Smtp:EnableSsl"])
        };
        var message = new MailMessage(_configuration["Smtp:From"], email, subject, htmlMessage)
        {
            IsBodyHtml = true
        };
        await client.SendMailAsync(message);
    }
}

注册服务到DI容器

在Program.cs中添加:

builder.Services.AddScoped<IEmailSender, EmailSender>();
builder.Services.AddScoped<ISmsSender, SmsSender>(); // 替换为你的短信实现类

3. 集成到用户认证流程

在自定义AccountController中注入UserManager<IdentityUser>和发送服务,处理关键流程:

注册并发送邮箱验证邮件

[ApiController]
[Route("api/[controller]")]
public class AccountController : ControllerBase
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly IEmailSender _emailSender;

    public AccountController(UserManager<IdentityUser> userManager, IEmailSender emailSender)
    {
        _userManager = userManager;
        _emailSender = emailSender;
    }

    [HttpPost("register")]
    public async Task<IActionResult> Register(RegisterModel model)
    {
        var user = new IdentityUser { UserName = model.Email, Email = model.Email };
        var result = await _userManager.CreateAsync(user, model.Password);

        if (result.Succeeded)
        {
            var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            var confirmationLink = Url.Action("ConfirmEmail", "Account", 
                new { userId = user.Id, token }, protocol: HttpContext.Request.Scheme);
            
            await _emailSender.SendEmailAsync(model.Email, "确认你的邮箱", 
                $"请点击链接确认邮箱:<a href='{confirmationLink}'>确认</a>");
            
            return Ok("注册成功,请查收邮件完成验证");
        }
        return BadRequest(result.Errors);
    }

    [HttpGet("confirm-email")]
    public async Task<IActionResult> ConfirmEmail(string userId, string token)
    {
        var user = await _userManager.FindByIdAsync(userId);
        if (user == null) return NotFound();
        var result = await _userManager.ConfirmEmailAsync(user, token);
        return result.Succeeded ? Ok("邮箱验证成功") : BadRequest("验证失败");
    }

    [HttpPost("forgot-password")]
    public async Task<IActionResult> ForgotPassword(ForgotPasswordModel model)
    {
        var user = await _userManager.FindByEmailAsync(model.Email);
        if (user != null && await _userManager.IsEmailConfirmedAsync(user))
        {
            var token = await _userManager.GeneratePasswordResetTokenAsync(user);
            var resetLink = Url.Action("ResetPassword", "Account", 
                new { email = model.Email, token }, protocol: HttpContext.Request.Scheme);
            
            await _emailSender.SendEmailAsync(model.Email, "重置你的密码", 
                $"请点击链接重置密码:<a href='{resetLink}'>重置</a>");
            // 如需短信验证,替换为调用ISmsSender发送含token的短信
        }
        return Ok("如果你的邮箱存在,我们已发送重置链接");
    }
}

4. 配置Identity选项

在Program.cs中配置令牌相关规则:

builder.Services.AddDefaultIdentity<IdentityUser>(options =>
{
    options.SignIn.RequireConfirmedAccount = true;
    options.Tokens.EmailConfirmationTokenProvider = "EmailConfirmation";
})
.AddTokenProvider<DataProtectorTokenProvider<IdentityUser>>("EmailConfirmation")
.AddEntityFrameworkStores<ApplicationDbContext>();

// 自定义令牌有效期
builder.Services.Configure<DataProtectionTokenProviderOptions>(options =>
{
    options.TokenLifespan = TimeSpan.FromHours(2); // 邮箱验证令牌2小时有效
});

5. 前端适配自定义API

修改React前端的请求逻辑,将原默认Identity API的调用地址,替换为自定义的/api/account/register、/api/account/forgot-password等端点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:10:16