0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BlazorとIdentity Coreで確認メールのURLからエスケープ文字を取り除く

Posted at

はじめに

BlazorとIdentity Coreで認証画面を作成した時に、確認メールのURLでパラメーターの一部が正しく処理されず、エラーになりました。

確認メールのURLをクリックすると、ConfirmEmail.cshtml.csのOnGetAsyncがコールされますが、userIdは値が必ず入りcodeの引数が必ずnullとなってしまいIndexに戻ってしまう、という現象になってしまいます。

ConfirmEmail.cshtml.cs
public async Task<IActionResult> OnGetAsync(string userId, string code)
{
    if (userId == null || code == null) // codeが常にnullなのでIndexに飛ばされる。
    {
        return RedirectToPage("/Index");
    }
    ...
}

メールで送られてきたURLパラメーターを見ると &amp;code= になっていました。amp;部分を削除すると正しく処理されたので、文字列をエンコードしている箇所に原因があるのだと思われます。

実際に届いたメールのURL.txt
https://ほげほげ/Identity/Account/ConfirmEmail?userId=ユーザーID&amp;code=コード値&amp;returnUrl=%2F

今回はメールに送られてきたURLから &amp; を取り除き正しく処理されるようにします。

環境

  • Windows 11
  • C#
  • Visual Studio 2022
  • .Net Core SDK 6.0.30
  • ASP.Net Core SDK 6.0.30

前提条件

以下の事を事前に行っています。

  • メールが送信できるよう設定済
  • .NET IdentityでLogin、Register、ConfirmEmailを作成

以下、IDからスキャッフォールディングした内容

Areaフォルダ内にあるIdentityフォルダを右クリックし、追加→新規スキャフォールディングアイテムを選択。
image.png

IDを選択し
image.png

IDの追加でLogin、Register、ConfirmEmailを追加
image.png

確認メールを行っている箇所の画面部分

実際にデバッグを行い、ユーザーの新規作成時にメールアドレス、パスワードを入力後のRegisterボタン実行後に確認メールが送られます。

image.png

ボタン入力後、OnPostAsyncに遷移しawait _emailSender.SendEmailAsyncでメール送信をおこないます。
ここで

HtmlEncoder.Default.Encode(callbackUrl)

となっている箇所を

callbackUrl

に修正します。

実際に修正したソースです。
※ 修正前のソース箇所をコメントアウトしています。

Register.cshtml.cs
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl ??= Url.Content("~/");
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
    if (ModelState.IsValid)
    {
        var user = CreateUser();

        await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
        await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
        var result = await _userManager.CreateAsync(user, Input.Password);

        if (result.Succeeded)
        {
            _logger.LogInformation("User created a new account with password.");

            var userId = await _userManager.GetUserIdAsync(user);
            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                protocol: Request.Scheme);

            //await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
            //    $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

            await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                $"Please confirm your account by <a href='{callbackUrl}'>clicking here</a>.");  // ここでHtmlEncoderを使わない

            if (_userManager.Options.SignIn.RequireConfirmedAccount)
            {
                return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
            }
            else
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }
)

修正後、再度同じ手順で実行すると、確認メールのURLに amp; が消えている事が確認できます。このURLからConfirmEmail.cshtml.csのOnGetAsyncの引数にcodeの値が入りメール登録できるようになります。

なぜ &amp; が問題になるのか

&amp;はHTMLエスケープシーケンスであり、HTML文書内では問題なく使用できますが、URLパラメータとして使う場合、特定の状況で問題が発生することがあります。

1.HTMLエスケープシーケンスの意味

&amp; はHTMLエスケープシーケンスで、HTML文書中の&文字を表します。ブラウザがHTML文書を解析するときに、&amp;は&に変換されます。

2.メールクライアントの処理

メールクライアントはHTMLをレンダリングする際に&amp;を&として表示しますが、リンクとして認識する場合に問題が発生することがあります。メールクライアントやウェブベースのメールサービスはリンクを正しく解釈しないことがあります(これは設定等にも影響がありそうですが)

3.URLのエンコードとデコードの処理

URLにエスケープシーケンスが含まれている場合、サーバーサイドでそのURLを受け取った際に正しくデコードされないことがあります。このため、パラメータの分離に失敗し、結果としてcodeがnullになることがあります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?