确认电子邮件中的 ASP.NET Core Identity 无效令牌 [英] ASP.NET Core Identity invalid token on confirmation email

查看:29
本文介绍了确认电子邮件中的 ASP.NET Core Identity 无效令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个非常相似的问题确认电子邮件中的aspnet身份无效令牌但解决方案无效,因为我使用的是包含 ASP.NET Core Identity 的新 ASP.NET Core 1.0.

我的场景如下:

  1. 在后端(ASP.NET Core)中,我有一个函数可以发送带有链接的密码重置电子邮件.为了生成该链接,我必须使用 Identity 生成代码.像这样的东西.

    public async Task SendPasswordResetEmailAsync(string email){//_userManager 是 UserManager 的一个实例var userEntity = await _userManager.FindByNameAsync(email);var tokenGenerated = await _userManager.GeneratePasswordResetTokenAsync(userEntity);var link = Url.Action("MyAction", "MyController", new { email = email, code = tokenGenerated }, protocol: HttpContext.Request.Scheme);//这是我的服务,它向用户发送包含生成的密码重置链接的电子邮件等待 _emailService.SendPasswordResetEmailAsync(userEntity , link);}

    这将生成一封带有链接的电子邮件:

    <代码> HTTP://MyApp的:8080/passwordreset代码= CfDJ8JBnWaVj6h1PtqlmlJaH57r9TRA5j7Ij1BVyeBUpqX + 5Cq1msu9zgkuI32Iz9x/5uE1B9fKFp4tZFFy6lBTseDFTHSJxwtGu + jHX5cajptUBiVqIChiwoTODh7ei4 + MOkX7rdNVBMhG4jOZWqqtZ5J30gXr/JmltbYxqOp4JLs8V05BeKDbbVO/Fsq5 + jebokKkR5HEJU + mQ5MLvNURsJKRBbI3qIllj1RByXt9mufGRE3wmQf2fgKBkAL6VsNgB8w ==

  2. 然后,我的 AngularJs 应用程序将显示一个视图,其中包含一个用于输入和确认新密码的表单,并将使用新密码和从 URL 中的查询参数获取的代码 PUT 一个 JSON 对象.

  3. 最后,我的后端会收到 PUT 请求,抓取代码并使用身份验证它,如下所示:

    [HttpPut][允许匿名][路由(api/密码/{email}")]公共异步任务SendPasswordEmailResetRequestAsync(string email, [FromBody] PasswordReset passwordReset){//这里有一些不相关的验证await _myIdentityWrapperService.ResetPasswordAsync(email, passwordReset.Password, passwordReset.Code);返回确定();}

问题是 Identity 以

响应<块引用>

无效令牌

错误.我发现问题是代码不匹配,上面的代码将在 PUT 请求的 JSON 对象中被接收,如下所示:

<预类= 朗 - 无prettyprint-越权"> <代码> CfDJ8JBnWaVj6h1PtqlmlJaH57r9TRA5j7Ij1BVyeBUpqX 5Cq1msu9zgkuI32Iz9x/5uE1B9fKFp4tZFFy6lBTseDFTHSJxwtGu jHX5cajptUBiVqIChiwoTODh7ei4 MOkX7rdNVBMhG4jOZWqqtZ5J30gXr/JmltbYxqOp4JLs8V05BeKDbbVO/Fsq5 jebokKkR5HEJU mQ5MLvNURsJKRBbI3qIllj1RByXt9mufGRE3wmQf2fgKBkAL6VsNgB8w ==

请注意,有 + 符号的地方现在有空格 符号,显然这导致 Identity 认为标记不同.出于某种原因,Angular 正在以不同的编码方式解码 URL 查询参数.

如何解决这个问题?

解决方案

这个答案 https://stackoverflow.com/a/31297879/2948212 为我指明了正确的方向.但正如我所说,它适用于不同的版本,现在它的解决方案略有不同.

答案还是一样:用base 64 url​​编码token,然后用base 64 url​​解码.这样 Angular 和 ASP.NET Core 将检索完全相同的代码.

我需要为 Microsoft.AspNetCore.WebUtilities;

安装另一个依赖项

现在代码应该是这样的:

public async Task SendPasswordResetEmailAsync(string email){//_userManager 是 UserManager 的一个实例var userEntity = await _userManager.FindByNameAsync(email);var tokenGenerated = await _userManager.GeneratePasswordResetTokenAsync(userEntity);byte[] tokenGeneratedBytes = Encoding.UTF8.GetBytes(tokenGenerated);var codeEncoded = WebEncoders.Base64UrlEncode(tokenGeneratedBytes);var link = Url.Action("MyAction", "MyController", new { email = email, code = codeEncoded }, protocol: HttpContext.Request.Scheme);//这是我的服务,它向用户发送包含生成的密码重置链接的电子邮件等待 _emailService.SendPasswordResetEmailAsync(userEntity , link);}

以及在 PUT 请求期间接收回代码时

[HttpPut][允许匿名][路由(api/密码/{email}")]公共异步任务SendPasswordEmailResetRequestAsync(string email, [FromBody] PasswordReset passwordReset){//这里有一些不相关的验证await _myIdentityWrapperService.ResetPasswordAsync(email, passwordReset.Password, passwordReset.Code);返回确定();}//在 MyIdentityWrapperService 中公共异步任务 ResetPasswordAsync(字符串电子邮件,字符串密码,字符串代码){var userEntity = await _userManager.FindByNameAsync(email);var codeDecodedBytes = WebEncoders.Base64UrlDecode(code);var codeDecoded = Encoding.UTF8.GetString(codeDecodedBytes);等待 _userManager.ResetPasswordAsync(userEntity, codeDecoded, password);}

This is a very similar question to this aspnet identity invalid token on confirmation email but the solutions are not valid because I am using the new ASP.NET Core 1.0 that includes ASP.NET Core Identity.

My scenario is as follows:

  1. In the back end (ASP.NET Core) I have a function that sends a password reset email with a link. In order to generate that link I have to generate a code using Identity. Something like this.

    public async Task SendPasswordResetEmailAsync(string email)
    {
        //_userManager is an instance of UserManager<User>
        var userEntity = await _userManager.FindByNameAsync(email);
        var tokenGenerated = await _userManager.GeneratePasswordResetTokenAsync(userEntity);
        var link = Url.Action("MyAction", "MyController", new { email = email, code = tokenGenerated }, protocol: HttpContext.Request.Scheme);
         //this is my service that sends an email to the user containing the generated password reset link
         await _emailService.SendPasswordResetEmailAsync(userEntity , link);
    }
    

    this would generate an email with a link to:

    http://myapp:8080/passwordreset?code=CfDJ8JBnWaVj6h1PtqlmlJaH57r9TRA5j7Ij1BVyeBUpqX+5Cq1msu9zgkuI32Iz9x/5uE1B9fKFp4tZFFy6lBTseDFTHSJxwtGu+jHX5cajptUBiVqIChiwoTODh7ei4+MOkX7rdNVBMhG4jOZWqqtZ5J30gXr/JmltbYxqOp4JLs8V05BeKDbbVO/Fsq5+jebokKkR5HEJU+mQ5MLvNURsJKRBbI3qIllj1RByXt9mufGRE3wmQf2fgKBkAL6VsNgB8w==

  2. Then my AngularJs application would present a view with a form to enter and confirm the new password, and would PUT a JSON object with the new password and the code that got from the query parameter in the URL.

  3. Finally my back end would get the PUT request, grab the code and validate it using Identity like this:

    [HttpPut]
    [AllowAnonymous]
    [Route("api/password/{email}")]
    public async Task<IActionResult> SendPasswordEmailResetRequestAsync(string email, [FromBody] PasswordReset passwordReset)
    {
        //some irrelevant validatoins here
        await _myIdentityWrapperService.ResetPasswordAsync(email, passwordReset.Password, passwordReset.Code);
        return Ok();
    }
    

The problem is that Identity responds with an

Invalid token

error. I have found that the problem is that the codes don't match and the above code would be received back in the JSON object in the PUT request as follows:

CfDJ8JBnWaVj6h1PtqlmlJaH57r9TRA5j7Ij1BVyeBUpqX 5Cq1msu9zgkuI32Iz9x/5uE1B9fKFp4tZFFy6lBTseDFTHSJxwtGu jHX5cajptUBiVqIChiwoTODh7ei4 MOkX7rdNVBMhG4jOZWqqtZ5J30gXr/JmltbYxqOp4JLs8V05BeKDbbVO/Fsq5 jebokKkR5HEJU mQ5MLvNURsJKRBbI3qIllj1RByXt9mufGRE3wmQf2fgKBkAL6VsNgB8w==

Notice that where there was + symbols now there are spaces symbols and obviously that causes Identity to think the tokens are different. For some reason Angular is decoding the URL query parameter in a different way that was encoded.

How to resolve this?

解决方案

This answer https://stackoverflow.com/a/31297879/2948212 pointed me in the right direction. But as I said it was for a different version and now it is slightly different solution.

The answer is still the same: encode the token in base 64 url, and then decode it in base 64 url. That way both Angular and ASP.NET Core will retrieve the very same code.

I needed to install another dependency to Microsoft.AspNetCore.WebUtilities;

Now the code would be something like this:

public async Task SendPasswordResetEmailAsync(string email)
{
    //_userManager is an instance of UserManager<User>
    var userEntity = await _userManager.FindByNameAsync(email);
    var tokenGenerated = await _userManager.GeneratePasswordResetTokenAsync(userEntity);
    byte[] tokenGeneratedBytes = Encoding.UTF8.GetBytes(tokenGenerated);
    var codeEncoded = WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
    var link = Url.Action("MyAction", "MyController", new { email = email, code = codeEncoded }, protocol: HttpContext.Request.Scheme);
     //this is my service that sends an email to the user containing the generated password reset link
     await _emailService.SendPasswordResetEmailAsync(userEntity , link);
}

and when receiving back the code during the PUT request

[HttpPut]
[AllowAnonymous]
[Route("api/password/{email}")]
public async Task<IActionResult> SendPasswordEmailResetRequestAsync(string email, [FromBody] PasswordReset passwordReset)
{
    //some irrelevant validatoins here
    await _myIdentityWrapperService.ResetPasswordAsync(email, passwordReset.Password, passwordReset.Code);
    return Ok();
}

//in MyIdentityWrapperService
public async Task ResetPasswordAsync(string email, string password, string code)
{
    var userEntity = await _userManager.FindByNameAsync(email);
    var codeDecodedBytes = WebEncoders.Base64UrlDecode(code);
    var codeDecoded = Encoding.UTF8.GetString(codeDecodedBytes);
    await _userManager.ResetPasswordAsync(userEntity, codeDecoded, password);
}

这篇关于确认电子邮件中的 ASP.NET Core Identity 无效令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆