我有两个使用相同ASP.NET核心身份后端的服务器。我使用以下代码生成密码重置令牌:
var token = await _userManager.GeneratePasswordResetTokenAsync(applicationUser);
我通过电子邮件链接发送此令牌。当用户单击该链接时,它们将被带到一个单独的站点,该站点应提供用于更改密码的UI。以下代码处理用户提交令牌及其新密码的密码:
var identityResult = await _userManager.ResetPasswordAsync(applicationUser, code, password);
在第二台服务器上,标识结果始终返回false,因为“无效标记”。
查看源代码,我看到令牌是使用IP地址生成的(所以我理解令牌验证失败的原因)。
我的问题是如何在不同的机器上启用成功的令牌创建/验证?在以前的ASP.NET形式中,我可能会使用共享机器密钥来阻止这些情况。 ASP.NET Core似乎没有类似的概念。根据我的阅读,似乎这可能是使用DataProtection API的场景。不幸的是,我没有看到任何关于如何将其应用于生成重置令牌的示例。
答案 0 :(得分:4)
您应该在发送令牌之前对其进行编码。你应该这样做:
var token = await _userManager.GeneratePasswordResetTokenAsync(applicationUser);
var encodedCode = HttpUtility.UrlEncode(token);
对其进行编码后,您必须传递编码的令牌而不是生成的令牌。
答案 1 :(得分:2)
您是否尝试在两个应用程序中将应用程序名称设置为相同的值?
services.AddDataProtection().SetApplicationName("same for both apps");
https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview
P.S - 我正在努力解决同样的问题。答案 2 :(得分:0)
我遇到了类似的问题。它实际上不是2台服务器。它关于身份框架。您可以从usermanager派生,并且可以使用中央管理器覆盖提供者。但我尝试了不同的东西,它的确有效。 首先,ConfirmEmail方法会查看数据库,如果您有一个数据库,那么在具有多个服务器的令牌之间应该不会出现问题。
在你的usermanager中,你应该在你的构造函数中创建dataprovider。
e.Arguments
此外,您应该在数据库表中看到用户的令牌。在这行代码之后。
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
var dataProtectorProvider = Startup.DataProtectionProvider;
var dataProtector = dataProtectorProvider.Create("My Identity");
this.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser, string>(dataProtector);
//this.UserTokenProvider.TokenLifespan = TimeSpan.FromHours(24);
}
当您在数据库中看到令牌时,请检查电子邮件是否相同。然后单击你的回调网址并更正网址的编码。
使用dataProtectorProvider;
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>");