You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

页面提交密码重置提示无效令牌,Postman调用却可正常成功

密码重置令牌无效问题排查与解决

通过生成的密码重置链接进入页面设置新密码时,系统提示“无效密码”,但用相同令牌在Postman中调用接口却能成功。已尝试对令牌做HttpUtility.UrlEncode和对请求中的Token做HttpUtility.UrlDecode,问题仍存在。

生成密码重置链接的方法

public async Task<string> Handle(GenerateRecoveryLinkQuery request, CancellationToken cancellationToken){
    var user = await _userManager.FindByNameAsync(request.Username);
    if (user == null)
    {
        throw new Exception("User not found.");
    }

    var token = await _userManager.GeneratePasswordResetTokenAsync(user);
    var resetUrl = $"{baseUrl}/Auth/ResetPassword?user={request.Username}&code={HttpUtility.UrlEncode(token)}";

    var save = new RecoveryLink();
    save.Username = request.Username;
    save.Link = resetUrl;
    await DB.SaveAsync(save);
    return resetUrl;
}

处理密码重置的视图

[HttpGet("Auth/ResetPassword")]
public IActionResult ResetPassword(string user, string code)
{
    ViewBag.Username = user;
    ViewBag.Code = code;

    return View("ResetPassword");
}

重置密码处理器

public async Task<String> Handle(ResetPasswordQuery request, CancellationToken cancellationToken)
{
    var user = await _userManager.FindByNameAsync(request.Username);
    if (user == null)
    {
        throw new Exception("User not found.");
    }
    var reset = await _userManager.ResetPasswordAsync(user, request.Token, request.newPassword);
    if (reset.Succeeded)
    {
        return "Success";
    }
    var error = reset.Errors.Select(x=>x.Description).ToArray();

    throw new Exception (error[0]);
}

问题分析

  1. URL自动解码与前端转义冲突:ASP.NET Core会自动对URL参数进行解码,所以ResetPassword方法接收的code已经是解码后的令牌。如果前端视图直接将该令牌放入表单字段,HTML的自动转义可能会修改令牌中的特殊字符(比如+被转成空格、&被转义等),导致提交的令牌与原始令牌不一致。
  2. 编码方式不匹配:HttpUtility.UrlEncode与ASP.NET Core默认的URL编码逻辑存在差异,可能导致编码后的令牌在传递过程中出现不可逆的转义。

解决方案

  1. 统一编码方式,避免重复处理
    生成链接时改用ASP.NET Core推荐的编码方式:

    var encodedToken = UrlEncoder.Default.Encode(token);
    var resetUrl = $"{baseUrl}/Auth/ResetPassword?user={UrlEncoder.Default.Encode(request.Username)}&code={encodedToken}";
    

    后端接收code参数时无需手动解码,框架会自动处理。

  2. 前端传递令牌时禁用HTML转义
    在视图中使用Html.Raw()输出令牌,避免HTML转义修改字符:

    <input type="hidden" name="Token" value="@Html.Raw(ViewBag.Code)" />
    
  3. Base64编码绕过URL/HTML转义问题
    生成链接时将令牌转为Base64格式:

    var base64Token = Convert.ToBase64String(Encoding.UTF8.GetBytes(token));
    var resetUrl = $"{baseUrl}/Auth/ResetPassword?user={request.Username}&code={base64Token}";
    

    视图方法中解码后再传递给前端:

    var token = Encoding.UTF8.GetString(Convert.FromBase64String(code));
    ViewBag.Code = token;
    
  4. 验证令牌一致性
    在重置密码处理器中添加日志,对比接收到的request.Token与Postman中使用的令牌是否完全一致,排查前端传递过程中的字符变更。

内容的提问来源于stack exchange,提问作者birsanzhar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 19:57:38