我需要通过链接确认用户的电子邮件,但ASP.Net Identity在此操作上失败。代码下面是我如何生成令牌:
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,如果它很重要,除了这个之外,一切都很完美。
答案 0 :(得分:2)
首先,您必须确定令牌是否正确。 在生成令牌上,记下该令牌并在此之后检查您的数据库。
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);
}
当您收到电子邮件检查链接时,它必须与callbackurl匹配。当你点击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");
}
在此方法中,您必须看到代码变量与您的身份表中的代码匹配。
Identity Framework也存在重要问题。开箱即用的MVC上没有依赖注入容器等。您必须创建自己的IoC。我总是喜欢结构图来做到这一点。因为终身经理比其他人更好(ninject,unity等)。此外,我正在使用当前用户对象来减少对数据库或会话管理器的请求。
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));
}
}
有了这个我总是为同一个用户使用相同的对象,我也防止对象引用问题和紧耦合问题。
答案 1 :(得分:2)
当+
符号丢失时,表示UrlEncoding问题。 +
表示空格,如果要保留空格,则应对code
内容进行编码,然后在调用ConfirmEmail
之前使用UserManager.ConfirmEmailAsync
方法对其进行解码。
编码时,+
变为%2B
,反之亦然。
使用HttpUtility.UrlEncode()
命名空间中的HttpUtility.UrlDecode()
和System.Web
。