邮箱确认失败

Email confirmation fails

我需要通过 link 确认用户的电子邮件,但 ASP.Net 身份验证失败。下面的代码是我如何生成令牌:

string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); // Return Opd+0yNG++ZXFpRS19A8j8OgI7dzCAKTYWotHYvuu0nyYsH4SIQS+bHwkbmqQDlwvGAy5fyxxUsu4yIzHwF+PD6QNPU+PwBnIDUGMC9++FkMlqegqHVKpA59qvbokfI0yByYqLoZfD1EUpWExddDN0BN/SVNSgOKlyzd928k+k4O2/TnfSf/JFj8x1NUKuaj

以及我如何尝试检查和确认它:

[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string userId, string code)
{
    if (userId == null || code == null)
    {
        Logger.Error(string.Format("userId: {0}, code: {1}", userId, code));
        return View("Error");
    }

    // args values: userId: b96bf253-62e1-4c5e-bf5f-5bc527df9fd9 code: Opd 0yNG  ZXFpRS19A8j8OgI7dzCAKTYWotHYvuu0nyYsH4SIQS bHwkbmqQDlwvGAy5fyxxUsu4yIzHwF PD6QNPU PwBnIDUGMC9  FkMlqegqHVKpA59qvbokfI0yByYqLoZfD1EUpWExddDN0BN/SVNSgOKlyzd928k k4O2/TnfSf/JFj8x1NUKuaj 
    var result = await UserManager.ConfirmEmailAsync(userId, code);

    if (result.Succeeded) // This is false
    {
        return View("ConfirmEmail");
    }

    Logger.Error(string.Concat<string>(result.Errors)); // Wrong marker
    return View("Error");
}

我在调试器中没有检查到空值。为什么会失败?

P.S。如果它很重要,我会使用 Npgsql,除此之外,一切都很完美。

首先您必须确定令牌是否正确。 在您生成的令牌上,记下该令牌并在之后检查您的数据库。

string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
UserManager.EmailService = new EmailService();
await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

这也是我的电子邮件服务以供检查。

public class EmailService : IIdentityMessageService
    {
        public System.Threading.Tasks.Task SendAsync(IdentityMessage message)
        {
            // Plug in your email service here to send an email.
            var mail = new MailMessage
            {
                Subject = message.Subject,
                Body = message.Body,
                IsBodyHtml = true
            };
            mail.To.Add(message.Destination);
            mail.From = new MailAddress("me@mail.com","me");
            var smtp = new SmtpClient
            {
                Host = "smtp.mail.com",
                Port = 25,
                UseDefaultCredentials = false,
                Credentials = new System.Net.NetworkCredential("me@mail.com", "password"),
                EnableSsl = true
            };
            // Enter seders User name and password

            smtp.Send(mail);

            return System.Threading.Tasks.Task.FromResult(0);
        }

当您收到电子邮件检查link时,它必须与回调url匹配。当你点击 url 这个方法应该被调用。

[AllowAnonymous]
        public async Task<ActionResult> ConfirmEmail(string userId, string code)
        {
            if (userId == null || code == null)
                return View("Error");             
            var result = await UserManager.ConfirmEmailAsync(userId, code);
            return View(result.Succeeded ? "ConfirmEmail" : "Error");
        }

在此方法中,您必须看到代码变量与您的身份代码匹配 table。

身份框架也存在重要问题。开箱即用的 MVC 上没有依赖注入容器等。您必须创建自己的 IoC。我总是喜欢用结构图来做这件事。因为终身经理比其他人更好(ninject,团结等)。此外,我正在使用当前用户对象来减少对数据库或会话管理器的请求。

public class CurrentUser : ICurrentUser
    {
        private readonly ApplicationDbContext _context;
        private readonly IIdentity _identity;
        private ApplicationUser _user;

        public CurrentUser(IIdentity identity, ApplicationDbContext context)
        {
            _identity = identity;
            _context = context;
        }

        public ApplicationUser User
        {
            get { return _user ?? (_user = _context.Users.Find(_identity.GetUserId())); }
        }
    }

在我的 MVC 注册表中(请检查结构图文档),我在

上注册了我需要的所有内容
public class MvcRegistry : Registry
    {
        public MvcRegistry()
        {
            For<BundleCollection>().Use(BundleTable.Bundles);
            For<RouteCollection>().Use(RouteTable.Routes);
            For<IIdentity>().Use(() => HttpContext.Current.User.Identity);
            For<IUserStore<ApplicationUser>>().Use<UserStore<ApplicationUser>>();
            For<DbContext>().Use(() => new ApplicationDbContext());
            For<IAuthenticationManager>().Use(() => HttpContext.Current.GetOwinContext().Authentication);
            For<HttpSessionStateBase>().Use(() => new HttpSessionStateWrapper(HttpContext.Current.Session));
            For<HttpContextBase>().Use(() => new HttpContextWrapper(HttpContext.Current));
            For<HttpServerUtilityBase>().Use(() => new HttpServerUtilityWrapper(HttpContext.Current.Server));
        }
    }

有了这个,我总是为同一个用户使用同一个对象,我也防止了对象引用问题和紧耦合问题。

+ 符号丢失时,表示 UrlEncoding 问题。 + 代表一个空格,如果你想保留它,你应该编码你的 code 内容,然后在调用 UserManager.ConfirmEmailAsync.[=20 之前在你的 ConfirmEmail 方法中解码它=]

编码时,+ 变为 %2B,解码时则相反。

使用 System.Web 命名空间中的 HttpUtility.UrlEncode()HttpUtility.UrlDecode()