“令牌无效”错误,同时电子邮件确认 ASP.NET MVC
本文关键字:电子邮件 确认 ASP MVC NET 无效 令牌 令牌无效 错误 | 更新日期: 2023-09-27 18:36:16
我正在尝试将注册和登录逻辑封装到MVC中的文件中。一切正常,但我总是收到"无效令牌"。 电子邮件确认程序后出错 :(
拜托,你能帮忙吗?在寻找解决方案两天后,我变得疯狂了!
我注意到 GenerateEmailConfirmationToken
方法总是生成不同的令牌,因为它显示在日志文件中。可以吗?如果未存储令牌,则它应该始终相同,对吗?
这是我准备 ASP.NET 管理器的存储库构造函数:
UserStore<MyUser> store = null;
UserManager<MyUser, string> userManager = null;
SignInManager<MyUser, string> signInManager = null;
IAuthenticationManager authenticationManager = null;
AbstractLogger logger = AbstractLogger.GetInstance();
public MyUserRepository(MyDbContext context) : base(context)
{
store = new UserStore<MyUser>(context);
userManager = new UserManager<MyUser>(store);
authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
signInManager = new SignInManager<MyUser, string>(userManager, authenticationManager);
userManager.PasswordValidator = new PasswordValidator()
{
RequireDigit = false,
RequiredLength = 6,
RequireLowercase = false,
RequireNonLetterOrDigit = false,
RequireUppercase = false
};
userManager.UserValidator = new UserValidator<MyUser>(userManager)
{
RequireUniqueEmail = true,
AllowOnlyAlphanumericUserNames = true
};
// Configure user lockout defaults
userManager.UserLockoutEnabledByDefault = true;
userManager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
userManager.MaxFailedAccessAttemptsBeforeLockout = 5;
userManager.EmailService = new EmailService();
var provider = new DpapiDataProtectionProvider("MyApp.org");
userManager.UserTokenProvider = new DataProtectorTokenProvider<MyUser, string>(provider.Create("UserToken")) as IUserTokenProvider<MyUser, string>;
}
以下是注册方法:
public void Register(MyUser user, string password)
{
IdentityResult result = userManager.Create(user, password);
//For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
//Send an email with this link
string code = string.Empty;
for (int i = 0; i < 10; i++)
{
code = userManager.GenerateEmailConfirmationToken(user.Id);
logger.LogInfo("USER: " + user.Id + " CODE: " + code);
}
logger.LogInfo(
string.Format(
"New user {0}; {1}; {2}",
user.Email,
user.Id,
code
));
string callbackUrl = string.Format("http://localhost:5320/Account/ConfirmEmail?userId={0}&code={1}", user.Id, code); // }, protocol: HttpContext.Current.Request.Url.Scheme);
userManager.SendEmail(user.Id, "Potvrzení registrace", "Please confirm your account by clicking <a href='"" + callbackUrl + "'">here</a>");
}
这是确认方法:
public IdentityResult ConfirmEmail(string userId, string code)
{
return userManager.ConfirmEmail(userId, code);
}
以下是日志输出:
USER: 1371ccfd-e8fd-46ed-8bfb-9d51f68aca63
CODE: AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAADOWwoIJFDEqzZ8IvsDocNQAAAAACAAAAAAAQZgAAAAEAACAAAABakUsHl8hIMJX5U5sOc4zEgxUY8ikanoiKoZyIJkttZgAAAAAOgAAAAAIAACAAAADeBcyc9fhA+UR93KdPyWf8zzbJJjAcleIzf4CHCTr3OmAAAABUmOOqZs1FhaSRTcT2gV4V7JRhXNqYuJxJzB0gbo5DDfX1d010qH7YYNe4+iBh6JwdpKXR4tmsPKpojUx3RyPTbKIU8X39CJGqeWAFXAnDZMWKH2ztSn5M5h8V1zrotZRAAAAAVbRUJlIZeKgN/FH5//NQWRBFqKc9GSq0TvMWkYgZeAOyIfTh+JAMoXA4FrYnmJswLZC44zmlZPdisKnsT81ArA==
USER: 1371ccfd-e8fd-46ed-8bfb-9d51f68aca63
CODE: AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAADOWwoIJFDEqzZ8IvsDocNQAAAAACAAAAAAAQZgAAAAEAACAAAABwzJP5VCa/GBicSwTV4Jwu2kt3XvX3xeklIFeJPiYB5QAAAAAOgAAAAAIAACAAAACfIv9bgzQJ9gwyc6Qhn/ml5iQU2qgvO83RiQGbEK/U32AAAACTT2WpFg2BdwLZzWI033SeNK3rUckzxkFkbeFGY7LlkuOhnrjsg/IMyv5YM8sFst8her1bPFi0NDvheSdIWIzWtBQFQZi2VuHRZz3+RiLQllIT/OS/94f1h+yx93QzIGhAAAAAVvPIboy1DrTKpv1easktkMW/olF+MT10MuNlQivcx5wDUSuvzql5GM6GY87Nkm1lFzp9+n0XNWEpbFRqilBuMA==
使用此UserManager.GeneratePasswordResetTokenAsync
方法来解决此问题。
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
return RedirectToAction("ResetPassword", "Account", new { userId = user.Id, code = code });
请使用 Url.Action 而不是使用字符串连接创建 url。Url.Action 在最新的 MVC 版本中在后台进行编码,您可以避免编码和解码操作。
下面是您可以使用的代码片段。
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new
{
userId = user.Id,
code = code,
returnUrl = model.ReturnUrl
}, protocol: Request.Url.Scheme);
如果不想使用Url.Action
则可以在生成 url 时使用 HttpUtility.UrlEncode(code);
对令牌进行编码
谢谢。问题实际上出在编码上。代码不应每次都相同。