web-dev-qa-db-ja.com

確認メールのASP.NETコアIDの無効なトークン

これはこれと非常によく似た質問です 確認メールのaspnet ID無効トークン しかし、ASP.NET CoreIdentityを含む新しいASP.NETCore 1.0を使用しているため、ソリューションは無効です。

私のシナリオは次のとおりです。

  1. バックエンド(ASP.NET Core)には、リンク付きのパスワードリセットメールを送信する機能があります。そのリンクを生成するには、Identityを使用してコードを生成する必要があります。このようなもの。

    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);
    }
    

    これにより、次のリンクが記載された電子メールが生成されます。

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

  2. 次に、AngularJsアプリケーションは、新しいパスワードを入力して確認するためのフォームを含むビューを表示し、新しいパスワードとURLのクエリパラメーターから取得したコードを使用してJSONオブジェクトを配置します。

  3. 最後に、私のバックエンドはPUTリクエストを取得し、コードを取得して、次のようにIdentityを使用して検証します。

    [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();
    }
    

問題は、Identityが

無効なトークン

エラー。問題は、コードが一致せず、上記のコードが次のようにPUTリクエストのJSONオブジェクトに返されることであることがわかりました。

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

+記号があったところにスペース記号があり、明らかにそれがIdentityにトークンが異なると思わせることに注意してください。何らかの理由でAngularは、エンコードされた別の方法でURLクエリパラメーターをデコードしています。

これを解決する方法は?

16
diegosasw

この答え https://stackoverflow.com/a/31297879/2948212 私を正しい方向に向けました。しかし、私が言ったように、それは別のバージョン用であり、今では少し異なる解決策です。

答えは同じです。トークンをbase64 url​​でエンコードしてから、base 64urlでデコードします。そうすれば、AngularとASP.NETCoreの両方がまったく同じコードを取得します。

Microsoft.AspNetCore.WebUtilities;に別の依存関係をインストールする必要がありました

これで、コードは次のようになります。

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);
}

pUTリクエスト中にコードを受信したとき

[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);
}
19
diegosasw

同様の問題があり、トークンをエンコードしていましたが、検証に失敗し続け、問題は次のようになりました:options.LowercaseQueryStrings = true;options.LowercaseQueryStringstrueを設定しないでくださいこれにより検証が変更されますトークンの整合性があり、無効なトークンエラーが発生します。

// This allows routes to be in lowercase
services.AddRouting(options =>
{
     options.LowercaseUrls = true;
      options.LowercaseQueryStrings = false;
});

3
yaddly

Asp.Net Core 3.0プロジェクトでConfirmEmailページをスキャフォールディングした後、同じ問題が発生しました。

_ConfirmEmail.cshtml.cs_のOnGetAsyncメソッドから次の行を削除すると、問題が修正されました。

_code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
_

スキャフォールドログインページで、codecallbackUrlに追加され、HtmlEncoder.Default.Encode(callbackUrl)を使用してURLエンコードされます。リンクがクリックされると、デコードが自動的に実行され、codeは電子メールを確認する必要があるようになります。

更新:

パスワードを忘れたプロセス中に、codecallbackUrlに配置される前にBase64でエンコードされていることに気付きました。これは、Base64デコード[〜#〜]は[〜#〜]必要です。

したがって、より良い解決策は、callbackUrlに追加する前に、コードが生成される場所に次の行を追加することです。

_code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
_

これが修正された issue へのリンクです。

3
jhhwilliams