身份密码重置令牌无效
Posted
技术标签:
【中文标题】身份密码重置令牌无效【英文标题】:Identity password reset token is invalid 【发布时间】:2015-02-21 10:45:45 【问题描述】:我正在编写 MVC 5 并使用 Identity 2.0。
现在我正在尝试重置密码。但我总是收到重置密码令牌的“无效令牌”错误。
public class AccountController : Controller
public UserManager<ApplicationUser> UserManager get; private set;
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
我设置了 DataProtectorTokenProvider,
public AccountController(UserManager<ApplicationUser> userManager)
//usermanager config
userManager.PasswordValidator = new PasswordValidator RequiredLength = 5 ;
userManager.EmailService = new IddaaWebSite.Controllers.MemberShip.MemberShipComponents.EmailService();
var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider();
userManager.UserTokenProvider = new Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider<ApplicationUser>(provider.Create("UserToken"))
as IUserTokenProvider<ApplicationUser, string>;
UserManager = userManager;
我在发送邮件之前生成密码重置
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ManagePassword(ManageUserViewModel model)
if (Request.Form["email"] != null)
var email = Request.Form["email"].ToString();
var user = UserManager.FindByEmail(email);
var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
//mail send
我点击邮件中的链接,我正在获取密码重置令牌并使用
var result = await UserManager.ResetPasswordAsync(model.UserId, model.PasswordToken, model.NewPassword);
结果总是假的,它说“无效令牌”。 我应该在哪里解决?
【问题讨论】:
您将生成的令牌存储在哪里? @vgSefa 在 Identity 中,令牌已签名,这意味着无需将它们存储在某处。 二看:是否生成了token?我认为在设置 UserTokenProvider 时不需要强制转换。也许那里出了点问题。 @Horizon_Net 是的,它生成并尝试移除铸件。还是不行 只是另一个想法:相应用户的电子邮件地址是否已经确认?如here 所述:如果未确认用户电子邮件,该方法会静默失败。如果针对无效电子邮件地址发布错误,恶意用户可以使用该信息找到有效的 userId(电子邮件别名)进行攻击。 好的,谢谢。我添加了电子邮件确认条件。 【参考方案1】:UserManager.GeneratePasswordResetTokenAsync()
经常返回包含“+”字符的字符串。如果您通过查询字符串传递参数,这就是原因('+' 字符是 URL 中查询字符串中的空格)。
尝试将model.PasswordToken
中的空格字符替换为“+”字符。
【讨论】:
另外,在我的情况下,追加“==”添加令牌的结尾。 或者发送邮件时使用WebUtility.UrlEncode(code),处理表单时使用WebUtility.UrDecode(Model.code) 请注意这个答案:***.com/a/13095475/453142 这是我的情况!! 我也是同样的问题,我无法从代码的最后一端获取“==”,所以如何处理这个我是通过邮件中的查询字符串发送的代码,我也试试这个 WebUtility。邮件中的 UrlEncode(code) 发送和获取时间 WebUtility.UrDecode(Model.code) 使用此但仍然遇到问题并结束获取无效令牌。 我也遇到了编码和解码的问题。它帮助我首先将令牌编码为 Base64,然后在读入时再次对其进行解码。对于字符串的编码/解码,请参阅***.com/questions/11743160/…【参考方案2】:[HttpPost]
[ValidateAntiForgeryToken]
publicasync Task<ActionResult> ManagePassword(ManageUserViewModel model)
if (Request.Form["email"] != null)
var email = Request.Form["email"].ToString();
var user = UserManager.FindByEmail(email);
var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
//before send mail
token = HttpUtility.UrlEncode(token);
//mail send
并在密码重置操作解码令牌HttpUtility.UrlDecode(token);
【讨论】:
不要忘记像这样在重置时解码令牌:var result = await UserManager.ResetPasswordAsync(user.Id, HttpUtility.UrlDecode(code), user.Password);
此编码/解码是我的项目中缺少的部分,因此我通过电子邮件发送的令牌无法正常工作。谢谢!【参考方案3】:
我发现当数据库中 AspNetUsers 表中的用户的 SecurityStamp 列为 NULL 时,也会发生“无效令牌”错误。 使用开箱即用的 MVC 5 Identity 2.0 代码时,SecurityStamp 不会为 NULL,但是在对 AccountController 进行一些自定义时,我们的代码中引入了一个错误,该错误会清除 SecurityStamp 字段中的值。
【讨论】:
启用唯一电子邮件地址强制并且手动插入违反该设置的用户时,更新安全标记可能会失败。【参考方案4】:这里有很多答案 URLEncode the token before send to get around the fact that the token (a base 64 encoding string) 通常包含“+”字符。解决方案还必须考虑到令牌以 '==' 结尾。
我一直在努力解决这个问题,事实证明,一个大型组织中的许多用户都在使用 Scanmail Trustwave Link Validator(r),它不是对称地编码和解码电子邮件链接中的 URLEncoded 字符串(在撰写本文时)。
最简单的方法是使用 Mateusz Cisek 的答案并发送一个非 URLEncoded 令牌,然后简单地将空格字符替换回 +。在我的例子中,这是在 Angular SPA 中完成的,因此 javascript 变为 $routeParams.token.replace(/ /g,'+')
。
这里需要注意的是,如果使用 AJAX 发送令牌并滚动您自己的查询字符串解析算法 - 许多示例将每个参数拆分为“=”,这当然不会包括末尾的“==”令牌。使用其中一种正则表达式解决方案或仅查找第一个“=”即可轻松解决。
【讨论】:
以上是关于身份密码重置令牌无效的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 手动生成重置密码令牌:收到错误“此密码重置令牌无效”
ASP.NET CORE Identity DataProtectionTokenProviderOptions 密码重置令牌无效
ASP.NET Core 2.2 - 密码重置在 Azure 上不起作用(无效令牌)