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

如何在ASP.NET MVC中实现类似Gmail的注册邮箱验证码功能

在ASP.NET MVC中实现邮箱验证后完成注册的流程

1. 数据库设计(基于ASP.NET Identity扩展)

如果使用默认ASP.NET Identity身份验证框架,直接扩展IdentityUser类添加必要字段:

public class ApplicationUser : IdentityUser
{
    // 标记用户是否已激活
    public bool IsActive { get; set; }
    // 邮箱验证码
    public string EmailVerificationCode { get; set; }
    // 验证码过期时间
    public DateTime? VerificationCodeExpiry { get; set; }
    // 自定义个人信息字段
    public string NickName { get; set; }
}

更新数据库迁移,生成包含上述字段的用户表。

2. 初始注册流程

创建包含用户名、邮箱、密码、昵称等字段的注册视图,提交到AccountController的Register Action:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser
        {
            UserName = model.UserName,
            Email = model.Email,
            NickName = model.NickName,
            IsActive = false, // 初始状态设为未激活
            VerificationCodeExpiry = DateTime.Now.AddMinutes(15) // 验证码15分钟过期
        };
        // 生成6位随机验证码
        user.EmailVerificationCode = new Random().Next(100000, 999999).ToString();

        // 将未激活用户存入数据库
        var result = await UserManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            await SendVerificationEmail(user);
            return RedirectToAction("VerifyEmail", "Account");
        }
        AddErrors(result);
    }
    // 模型验证失败时返回注册页面
    return View(model);
}

3. 发送验证邮件

实现邮件发送逻辑,可使用SmtpClient或第三方库(如MailKit):

private async Task SendVerificationEmail(ApplicationUser user)
{
    var verificationLink = Url.Action("ConfirmEmail", "Account", 
        new { userId = user.Id, code = user.EmailVerificationCode }, 
        protocol: Request.Url.Scheme);

    var emailBody = $"请点击链接完成验证:<a href='{verificationLink}'>验证邮箱</a> " +
                    $"或手动输入验证码:{user.EmailVerificationCode}";

    var message = new MailMessage
    {
        From = new MailAddress("your-email@example.com"),
        Subject = "账号注册邮箱验证",
        Body = emailBody,
        IsBodyHtml = true
    };
    message.To.Add(user.Email);

    using (var smtpClient = new SmtpClient("smtp.example.com", 587))
    {
        smtpClient.Credentials = new NetworkCredential("your-email@example.com", "your-password");
        smtpClient.EnableSsl = true;
        await smtpClient.SendMailAsync(message);
    }
}

注意:生产环境中需将SMTP配置写入Web.config,避免硬编码账号密码。

4. 邮箱验证流程

提供两种验证方式:点击邮件链接或手动输入验证码,对应以下Action:

// 处理邮件链接跳转的GET请求
[HttpGet]
[AllowAnonymous]
public ActionResult ConfirmEmail(string userId, string code)
{
    if (userId == null || code == null) return View("Error");
    
    var user = UserManager.FindById(userId);
    if (user == null) return View("Error");

    // 验证验证码有效性及过期时间
    if (user.EmailVerificationCode == code && user.VerificationCodeExpiry > DateTime.Now)
    {
        // 激活用户并清空验证码相关字段
        user.IsActive = true;
        user.EmailVerificationCode = null;
        user.VerificationCodeExpiry = null;
        UserManager.Update(user);
        return View("RegistrationSuccess");
    }
    return View("InvalidVerificationCode");
}

// 处理手动输入验证码的POST请求
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> VerifyEmail(VerifyEmailViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = await UserManager.FindByEmailAsync(model.Email);
        if (user != null && user.EmailVerificationCode == model.Code 
            && user.VerificationCodeExpiry > DateTime.Now)
        {
            user.IsActive = true;
            user.EmailVerificationCode = null;
            user.VerificationCodeExpiry = null;
            await UserManager.UpdateAsync(user);
            return RedirectToAction("RegistrationSuccess", "Account");
        }
        ModelState.AddModelError("", "验证码无效或已过期");
    }
    return View(model);
}

5. 限制未激活用户登录

修改登录逻辑,添加账号激活状态检查:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var user = await UserManager.FindByNameAsync(model.UserName);
        if (user != null)
        {
            if (!user.IsActive)
            {
                ModelState.AddModelError("", "账号尚未激活,请检查邮箱完成验证");
                return View(model);
            }
            var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
            switch (result)
            {
                case SignInStatus.Success:
                    return RedirectToLocal(returnUrl);
                case SignInStatus.LockedOut:
                    return View("Lockout");
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "无效的登录尝试");
                    return View(model);
            }
        }
        ModelState.AddModelError("", "无效的登录尝试");
        return View(model);
    }
    return View(model);
}

6. 可选:重新发送验证码

添加重新发送功能,方便用户在验证码过期后获取新码:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResendVerificationCode(string email)
{
    var user = await UserManager.FindByEmailAsync(email);
    if (user != null && !user.IsActive)
    {
        user.EmailVerificationCode = new Random().Next(100000, 999999).ToString();
        user.VerificationCodeExpiry = DateTime.Now.AddMinutes(15);
        await UserManager.UpdateAsync(user);
        await SendVerificationEmail(user);
        return Json(new { success = true, message = "验证码已重新发送,请检查邮箱" });
    }
    return Json(new { success = false, message = "该邮箱未注册或已激活" });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:55:55