WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

Email Confirmation の実装 (MVC5)

by WebSurfer 2021年3月16日 21:22

.NET Framework 版の ASP.NET MVC5 で ASP.NET Identity をユーザー認証に使用し、Email Confirmation を実装する方法を備忘録として書いておきます。

Email Confirmation

以前は Microsoft のチュートリアル「ログイン、電子メール確認、パスワード リセットを使用して安全な ASP.NET MVC 5 Web アプリを作成する (C#)」に従って生成されたコードに手を加えれば実装できたのですが、SendGrid が id と password による認証をサポートしなくなり、Api Key による認証を使うように変更する必要が生じました。

Core 版の MVC アプリ用には Api Key による認証を使う SendGrid による Email Confirmation のチュートリアルがあります(先の記事「Email Confirmation の実装 (CORE)」とそれからリンクが貼ってある Microsoft の記事を見てください)。それを参考に実装してみました。以下にその概要を書きます。

(1) プロジェクトの作成

Visual Studio 2019 の[新規作成(N)]⇒[プロジェクト(P)...]で「新しいプロジェクト」ダイアログを表示し、その中の「ASP.NET Web アプリケーション (.NET Framework)」テンプレートを選択して ASP.NET MVC アプリを作成します。

ASP.NET MVC アプリの作成

ASP.NET Identity による認証を実装する必要がありますので、上の画像のように認証に「個別のユーザーアカウント」を使用するように設定してください。

テンプレートで自動生成された認証関係のコードに手を加えて Email Confirmation の機能を実装します。

テンプレートが生成したデフォルトのコードでは、Accout/Register アクションメソッドでユーザーが登録に成功すると直ちにログインした状態になります。アクションメソッドにはメールを送信するコードが含まれていますがコメントアウトされています。

App_Data/IdentityConfig.cs ファイルに EmailService クラスというメール送信のためのクラスが定義されていて、クライアントからの要求を受けるとインスタンス化されて ApplicationUserManager に登録されます。ただし、EmailService クラスの SendAsync メソッドの中身が実装されてないのでメールを送ることはできません。

メールを送信するためには SendAsync メソッドに SendGrid を利用したメール送信機能を実装します。そして、Accout/Register に含まれているメール送信のためのコードのコメントアウトを解除します。

そうすることにより、ユーザー登録完了時点で登録したメールアドレスにメールが送信されます。ユーザーが受け取ったメール本文に含まれる url をクリックすると Accout/ConfirmEmail にクエリ文字列で設定された情報が送信され、サーバー側ではそれを確認してデータベースの AspNetUsers テーブルの EmailConfirmed フィールドを ture に設定します。

Account/Login アクションメソッドには、EmailConfirmed フィールドが ture になっている場合のみログインを許可するコードを追加します。これによりユーザーが送られてきたメール本文に含まれる url をクリックしない限りログインできないということになります。

(2) API Key の入手

メールの送信には SendGrid を利用します。ユーザー登録して API Key を入手してください。(先の記事「Email Confirmation の実装 (CORE)」のステップ (3) を見てください)

SendGrid は基本的に有償ですが、開発目的で送信するようなメールの数が少ない(一日 100 件以内だそうです)の場合は Free のサービスでよさそうです。

(3) SendGrid のインストール

NuGet を利用してプロジェクトに SendGrid をインストールします。

SendGrid をインストール

この記事では自分がインストールした時点での最新版 v9.22.0 を使いました。Microsoft のチュートリアル「ログイン、電子メール確認、パスワード リセットを使用して安全な ASP.NET MVC 5 Web アプリを作成する (C#)」にある SendGrid.Net40 とは違うので注意してください(それも一緒にインストールされますが)。

(4) API Key の保存

メールの差出人と SendGrid の API Key は web.config に保存します。暗号化などを考えた方が良いのかもしれませんが、この記事では簡略化のため生の Api Key を保存しています。

<appSettings>
  <add key="SendGridUser" value="WebSurfer" />
  <add key="SenGridKey" value="SG...t-A" />
</appSettings>

(5) EmailSender クラスの実装

メールを送信するため App_Data/IdentityConfig.cs の EmailService クラスにメール送信機能を実装します。

Microsoft のチュートリアル「Account confirmation and password recovery in ASP.NET Core」にあるコードを参考に以下のようにしました。

using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Mvc5EmailConfirmation.Models;

using SendGrid;
using SendGrid.Helpers.Mail;
using System.Configuration;

namespace Mvc5EmailConfirmation
{
    public class EmailService : IIdentityMessageService
    {
        public Task SendAsync(IdentityMessage message)
        {
            return Execute(ConfigurationManager.AppSettings["SenGridKey"], 
                       message.Subject, message.Body, message.Destination);
        }

        public Task Execute(string apiKey, string subject, 
                            string message, string email)
        {
            var client = new SendGridClient(apiKey);
            var msg = new SendGridMessage()
            {
                From = new EmailAddress("差出人メールアドレス",
                       ConfigurationManager.AppSettings["SendGridUser"]),
                Subject = subject,
                PlainTextContent = message,
                HtmlContent = message
            };
            msg.AddTo(new EmailAddress(email));

            msg.SetClickTracking(false, false);

            return client.SendEmailAsync(msg);
        }
    }

    // ・・・中略・・・
}

Core 版 MVC のチュートリアルの場合は Register メソッドから宛先メールアドレス、Subject、本文が直接渡されるのですが、.NET Framework 版 MVC5 のテンプレートで生成される SendAsync メソッドには UserManager 経由で IdentityMessage オブジェクトが渡されます。

その中に宛先メールアドレス、Subject、本文が含まれていますので、それぞれ Destination, Subject, Body プロパティを使って取得しています。

(6) Account/Register ページの修正

テンプレートで生成された SignInManager.SignInAsync メソッドをコメントアウトし、code の生成、メール本文に含める Accout/ConfirmEmail への url 作成、メール送信のためのコードのコメントアウトを解除します。

さらに、Home/Index にリダイレクトする既存のコードをコメントアウトし、代わりに登録完了後メール確認を促すページ Info を表示するようコードを追加します。Views/Shared/Info.cshtml をチュートリアルに従い作成・追加してください。

修正後のコードは以下の通りです。(修正は POST 側のみで GET 側は不要です)

// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser 
        { 
            UserName = model.Email, 
            Email = model.Email 
        };

        var result = await UserManager.CreateAsync(user, 
                                                   model.Password);

        if (result.Succeeded)
        {
            // 登録時にはログインさせないようコメントアウト
            //await SignInManager.SignInAsync(user, 
            //                                isPersistent:false, 
            //                                rememberBrowser:false);

            // code の生成、メール本文に含める Accout/ConfirmEmail
            // への url 作成(既存のコードのコメントアウトを解除)
            string code = await UserManager
                          .GenerateEmailConfirmationTokenAsync(user.Id);
            var callbackUrl = Url.Action("ConfirmEmail", 
                              "Account", 
                              new { userId = user.Id, code = code }, 
                              protocol: Request.Url.Scheme);

            // メール送信。既存のコードのコメントアウト解除でもよいが、
            // ユーザーのメーラーが html の表示を許可していない可能性を
            // 考えて、html の a 要素を組み立てて送るのではなく、url そ
            // のものを送信するように変更した
            await UserManager.SendEmailAsync(user.Id, "Confirm your email",
                "Please confirm your account by: " +
                Server.HtmlEncode(callbackUrl).Replace("&amp;", "&"));

            // メール確認を促すページ Info に表示するメッセージ
            ViewBag.Message = "Check your email and confirm your account," +
                " you must be confirmed before you can log in.";

            // チュートリアルに従い Views/Shared/Info.cshtml を別途作成要
            return View("Info");

            // これはコメントアウト
            //return RedirectToAction("Index", "Home");
        }
        AddErrors(result);
    }
    return View(model);
}

以上により、ユーザーが登録に成功するとこの記事の一番上の画像のとおり Info ページが表示され、ユーザーにメール確認を促します。

さらに、ユーザーが登録したメールアドレスに以下のメールが送信されます。メール本文にある url が Accout/ConfirmEmail となっており、クエリ文字列に userId と code が設定されています。ユーザーがこれをクリックすることにより Accout/ConfirmEmail に userId と code が送信され、メール確認が完了します(AspNetUsers テーブルの EmailConfirmed フィールドが ture に設定されます)。

確認メール

(7) Account/Login ページの修正

EmailConfirmed フィールドが ture になっているか否かを確認し true の場合のみログインを許可するコードを追加します。これによりユーザーが送られてきたメール本文に含まれる url をクリックしない限りログインできないということになります。

さらに、メール確認なしでログインしようとするとエラーメッセージを表示するためのコードも追加します。メッセージは Error ページ表示しますので、チュートリアルに従い Views/Shared/Error.cshtml を書き換えてください。

修正後のコードは以下の通りです。(修正は POST 側のみで GET 側は不要です)

// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, 
                                      string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    // メール確認がされてない場合はログインできないようにする
    var user = await UserManager.FindByNameAsync(model.Email);
    if (user != null)
    {
        if (!await UserManager.IsEmailConfirmedAsync(user.Id))
        {
            ViewBag.errorMessage = 
                "You must have a confirmed email to log on.";

            // チュートリアルに従い Views/Shared/Error.cshtml 
            // を書き換えないと上のエラーメッセージは表示され
            // ないので注意
            return View("Error");
        }
    }

    var result = await SignInManager
                 .PasswordSignInAsync(model.Email, 
                                      model.Password, 
                                      model.RememberMe, 
                                      shouldLockout: false);
    switch (result)
    {
        case SignInStatus.Success:
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("SendCode", 
                new { ReturnUrl = returnUrl, 
                      RememberMe = model.RememberMe });
        case SignInStatus.Failure:
        default:
            ModelState.AddModelError("", "無効なログイン試行です。");
            return View(model);
    }
}

次はユーザーがパスワードを忘れてしまった場合の Password Recovery の実装ですが、この記事で続けると長くなりすぎるので別の記事「Password Recovery の実装 (MVC5)」に書きます。

Tags: , ,

MVC

Web Forms アプリの Email Confirmation

by WebSurfer 2020年8月10日 14:05

ASP.NET Web Forms アプリで登録・パスワード再取得のためのメール送信機能を利用する場合、テンプレートで実装されたコードを使うとメール本文に含まれる確認先の URL にアプリケーション名が含まれないという注意事項を書きます。(結果、メール本文に張られたリンクの URL が正しくないのでクリックしても確認できません)

アプリケーション名が含まれない

.NET Framework 版の ASP.NET Web Forms の Web アプリケーションプロジェクトを Visual Studio 2019 のテンプレートを使って、ユーザー認証に「個別のユーザーアカウント」(ASP.NET Identity) を選んで作った場合の話です。ASP.NET MVC5 ではこの問題はありません。

元の話は Teratail のスレッド「リセット画面のURLをアプリケーションルートにしたい」のものです。そのスレッドを見て初めてそういう問題があることを知りました。

メール本文に含めて送信する確認先の URL は、Models/IdentityModels.cs に含まれるヘルパーメソッド GetUserConfirmationRedirectUrl と GetResetPasswordRedirectUrl で Uri(Uri, String) コンストラクタを使って取得しています。

Uri(Uri, String) コンストラクタの第 1 引数に HttpRequest.Url プロパティで取得する Uri を、第 2 引数に "/Account/..." から始まる相対 URL の文字列を設定して Uri オブジェクトを作り、それから AbsoluteUri プロパティを使って絶対 URL を取得して確認メールの本文に張り付けています。

この記事の一番上のデバッグ画像を見てください。問題のヘルパーメソッド GetUserConfirmationRedirectUrl, GetResetPasswordRedirectUrl ではないですが、簡単に問題を再現するために Page_Load メソッドに同等のコードを書いて検証してみました。

なお、Visual Studio (IIS Express) では以下のように Request.Uri にアプリケーション名 myapp が含まれるよう[プロジェクトの URL (J)]を設定しています。

アプリケーション名 myapp を設定

上のデバッグ画像のとおり、ローカル変数の rquestUri にはアプリケーション名 myapp を含めた Uri オブジェクトを取得できています。ローカル変数 callbackUrl が確認先の URL になりますが、アプリケーション名 myapp は含まれません。これが問題です。

ちなみに、ASP.NET MVC アプリでは Url.Action を使ってアプリケーション名を含めた絶対 URL を取得していますのでこういう問題はないです。

対処方法として、ヘルパーメソッド GetUserConfirmationRedirectUrl と GetResetPasswordRedirectUrl 内にアプリケーション名をハードコーディングするのは好ましくはなさそうです。アプリケーション名の変更、アプリの移植で問題となりますので。

ルート演算子 (~) と VirtualPathUtility.ToAbsolute メソッドを利用して "~" に相当するパスを取得するのがよさそうです。具体例は以下の画像を見てください。

VirtualPathUtility.ToAbsolute メソッド利用

この記事の例のように、アプリケーション名が myapp の場合、VirtualPathUtility.ToAbsolute メソッドの引数に "~" を設定すると戻り値は "/myapp" になります。引数に "~/Account/ResetPassword" を設定すると(文字列先頭に "~" を付与している点に注意)戻り値は "/myapp/Account/ResetPassword" となります。以下の画像を見てください。

このようにすればアプリケーション名をハードコーディングしなくて済みます。


その他のパス設定の問題

テンプレートで生成されたコードのパス設定の問題は他にもあって、例えば Account/Manage.aspx ページでも以下のようにリンク先の URL にルート演算子 (~) が設定されてないです。

URL にルート演算子 (~) が設定されてない

リンクをクリックしても、普通はパスが通らないので、404 Not Found エラーとなってすぐ気が付くと思うかもしれませんが、開発環境ですと訳が分からないサーバーエラーになることがあるかもしれません。

実は、上の画像にあるように Visual Studio で[プロジェクトの URL (J)]を設定したのですが、その際 IIS Express 用の applicationHost.config 設定で application path="/" と application path="/myapp" が両方有効になって、/Account/ManagePassword.aspx に遷移できてしまったのです。

認証チケットは /mayapp/Acount/Login.aspx で取得しているのですが、/Account/ManagePassword.aspx では認証されないので User.Identity.GetUserId() でユーザー ID を取得できず訳が分からないサーバーエラーになりました。

これには半日ぐらい悩まされました。どうも Microsoft としては Web Forms アプリには力が入ってなくて、テンプレートで生成されるコードでも 100% 信頼できないような感じがします。

Tags: , ,

ASP.NET

Email Confirmation の実装 (CORE)

by WebSurfer 2020年5月18日 16:12

ASP.NET Core 3.1 MVC で ASP.NET Identity をユーザー認証に使用し、Email Confirmation と Password Recovery を実装する際、自分的に気になったことを備忘録として書いておきます。

(.NET Framework 版については特に気を付ける点はなさそうなので割愛します。手抜きですみません。基本的な枠組みが Visual Studio のテンプレートで生成されるコードに含まれており、Microsoft のチュートリアル「ログイン、電子メール確認、パスワード リセットを使用して安全な ASP.NET MVC 5 Web アプリを作成する (C#)」に従って生成されたコードに手を加えれば特に苦労なく実装できると思います。 2021/3/14 追記: SendGrid は id と password による認証をサポートしなくなりました。なので、.NET Framework 版 MVC5 の場合もこの記事に書いた Api Key による認証とする必要がありますので注意してください

基本的には Microsoft のチュートリアル Account confirmation and password recovery in ASP.NET Core に従って実装しますので、詳しくはそのドキュメントを見てください。そのドキュメントの説明だけではよく分からないと思った点を以下に書きます。

(1) プロジェクトの作成

Visual Studio 2019 のテンプレートを利用して ASP.NET Core 3.1 MVC アプリを作成します。

認証関係のソースコードに手を加えるので、アプリ作成の際に認証は「認証なし」のままとしておき、スキャフォールディング機能を利用して ASP.NET Identity を実装し、ソースコードがプロジェクトに含まれるようにします。

詳しい手順は先の記事「ASP.NET Identity で MySQL 利用 (CORE 版)」のステップ「(1) プロジェクトの作成」とステップ「(2) ASP.NET Core Identity の実装」を見てください。

(2) Email Confirmation 実装前の動き

上のステップ (1) でプロジェクトを作成直後(Email Confirmation を実装する前)のユーザー登録の仕組み説明します。それを理解しておいた方がこの後の説明が分かりやすいと思いますので。仕組みをご存じの方はここはスキップして (3) に進んでください。

デフォルトで options.SignIn.RequireConfirmedAccount が true に設定されており(そのコードは Areas/Identity/IdentityHostingStartup.cs にあります)、ユーザー登録に使用する Register ページも Email Confirmation を使用する前提でコーディングされています。ちなみに false に設定すると登録後直ちにログイン状態になります。

Areas/Identity/Pages/Account フォルダにある Register.cshtml.cs を開いて OnPostAsync メソッドのコードを見てください。登録画面にユーザーが email と password を入力して送信するとそのメソッドでユーザー登録処理が行われます。

ユーザー登録に成功すると RegisterConfirmation ページにリダイレクトされます。(実際はリダイレクト前に _emailSender.SendEmailAsync メソッドが実行されますが、デフォルトではメール送信機能は実装されていないので何も起こりません。何故かエラーも出ません)

RegisterConfirmation ページは下の画像のように表示されます。

RegisterConfirmation ページ

上の画像の "Click here to confirm your account" には ConfirmEmail ページへのリンクが張ってあり、クエリ文字列に UserId とトークンが設定されています。

リンクをクリックすると ConfirmEmail ページが GET 要求され Areas/Identity/Pages/Account フォルダにある ConfirmEmail.cshtml.cs の _userManager.ConfirmEmailAsync(user, code) メソッドで Email Confirmation が実行(AspNetUsers テーブルの EmailConfirmed フィールドが True に更新)されます。

Email Confirmation に成功すると下の画像の ConfirmEmail ページが表示されます。

ConfirmEmail ページ

この後、右上の [Login] をクリックして Login ページを表示し、登録した email と password を入力してログインできるようになります。

Email Confirmation を実装してメールを送信できるようにすると、ConfirmEmail ページへのリンク(UserId とトークンのクエリ文字列を含む)が本文に含まれたメールが自動的に送信され、それをクリックすると ConfirmEmail ページが GET 要求されて Email Confirmation が実行されるようになります。

RegisterConfirmation ページへのリダイレクトは同様に起こりますが、それには ConfirmEmail ページへのリンクは含まれず、単に "Please check your email to confirm your account." と表示されただけものになります。

以下のステップ (3) 以降にメールの自動送信を含む Email Confirmation の実装方法を述べます

(3) API Key の入手

チュートリアルに従って、メールの送信には SendGrid を利用します。ユーザー登録して API Key を入手してください。

API Key の入手

SendGrid は基本的に有償ですが、開発目的限定で送信する量が少ない場合は Free のサービスでよさそうです。Pricing のページを見てください。

(4) SendGrid のインストール

NuGet を利用してプロジェクトに SendGrid をインストールします。

SendGrid をインストール

上の画像ではバージョンが 9.12.6 となっていますが、自分が試したときはそれが最新版だったということで、意図的にそのバージョンを選んだわけではありません。

(5) User Secrets

メールの差出人と SendGrid の API Key をユーザーシークレットに設定します。チュートリアルは dotnet コマンドを使っていますが、Visual Studio のソリューションエクスプローラーから開いて設定できます。

ユーザーシークレットの管理

上の画像のように操作すると secrets.json ファイルが開くので、それに以下のようにメールの差出人と SendGrid の API Key を設定して保存します。

secrets.json

appsettings.json に設定しても取得できますが、チュートリアルでは、開発時に、Password その他の機密データを秘密の場所に保存できることを紹介する意味でユーザーシークレットを使っているようです。

ユーザーシークレットは開発時の開発マシンのでの利用に限られます。secrets.json ファイルは開発マシンの開発者のユーザープロファイルフォルダー内にあるので当たり前ですが・・・ 詳しくは Safe storage of app secrets in development in ASP.NET Core を見てください。

チュートリアルには AuthMessageSenderOptions クラスの追加と Startup.ConfigureServices へのコードの追加を行うように書かれています。

まず、プロジェクトルート直下に Services フォルダを追加し、その中にクラスファイル AuthMesageSenderOptions.cs を追加します。コードはチュートリアルのものをコピペします。

// AuthMessageSenderOptions クラスの追加

namespace MySQLIdentity.Services
{
    public class AuthMessageSenderOptions
    {
        public string SendGridUser { get; set; }
        public string SendGridKey { get; set; }
    }
}

次に、Startup.cs の ConfigureServices メソッド内に以下のコードを追加します。

// Startup,cs の ConfigureServices メソッド内に追加

services.Configure<AuthMessageSenderOptions>(Configuration);

これらは、AuthMessageSenderOption クラスを、必要に応じて初期化してそのオブジェクトを DI によって注入するために必要なもののようです。

その設定により、secrets.json ファイルに設定した差出人と API Key 情報は、EmailSender クラスを初期化する際に DI によって注入された AuthMessageSenderOption オブジェクトから取得できます。

なお、secrets.json ファイルを使わなくても、普通に appsettings.json に差出人と API Key 情報を設定しても同様に DI によって取得できます(secrets.json と appsettings.json の両方から探してくるようです)。運用環境にデプロイする際に appsettings.json に移すということではなさそうですが、実際どうすべきかは調べておらず不明です。

(6) EmailSender クラスの実装

メールを送信するため IEmailSender インターフェイスを継承した EmailSender クラスを実装します。

チュートリアルに従ってクラスファイル Services/EmailSender.cs を追加し、それにチュートリアルのコードをそのままコピペしてください。

念のため、以下にコードを貼っておきます。

using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using SendGrid;
using SendGrid.Helpers.Mail;
using System.Threading.Tasks;

namespace MySQLIdentity.Services
{
    public class EmailSender : IEmailSender
    {
        public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor)
        {
            Options = optionsAccessor.Value;
        }

        public AuthMessageSenderOptions Options { get; }

        public Task SendEmailAsync(string email, string subject, string message)
        {
            return Execute(Options.SendGridKey, subject, message, email);
        }

        public Task Execute(string apiKey, string subject, string message, string email)
        {
            var client = new SendGridClient(apiKey);
            var msg = new SendGridMessage()
            {
                From = new EmailAddress("xxxxx", Options.SendGridUser),
                Subject = subject,
                PlainTextContent = message,
                HtmlContent = message
            };
            msg.AddTo(new EmailAddress(email));

            // Disable click tracking.
            // See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
            msg.SetClickTracking(false, false);

            return client.SendEmailAsync(msg);
        }
    }
}

上のコード From = new EmailAddress("xxxxx", Options.SendGridUser) の xxxxx をメールの差出人のメールアドレスに変更してください。

EmailSender クラスが初期化される際に DI により AuthMessageSenderOptions オブジェクトが注入され、差出人と API Key 情報が取得できるようにコーディングされています。

EmailSender クラスは Register ページと ForgotPassword ページでメールを送信する際に使用されます。その際、DI により EmailSender クラスを初期化してそのオブジェクトを注入するコーディングになっています。それを可能にするため、Startup.cs の ConfigureServices メソッド内に以下のコードを追加します。

// Startup.cs の ConfigureServices メソッド内に追加

services.AddTransient<IEmailSender, EmailSender>();

上記の Startup.cs への設定を忘れるとメール送信機能は動きませんので注意してください。

(7) Register ページの修正

Areas/Identity/Pages/Account フォルダの Register.cshtml.cs を開いて OnPostAsync メソッドのコードを見てください。

ユーザー登録に成功すると変数 callbackUrl に UserId とトークン情報がクエリ文字列として設定された /Account/ConfirmEmail ページへの URL 文字列が設定されます。

デフォルトでは html の a 要素の href 属性にその URL が設定されたメール本文がユーザーが email として登録したメールアドレスに送信されます。

ユーザーが使っているメーラーが html を表示できる設定になっていれば、その a 要素で "clicking here" と表示されるリンクをクリックすれば ConfirmEmail ページが GET 要求され、クエリ文字列に設定された UserId とトークンで Email Confirmation が行われ、ブラウザが立ち上がって ConfirmEmail ページが表示されます。

ユーザーのメーラーが html の表示を許可していない可能性を考えて、html の a 要素を組み立てて送るのではなく、URL そのものを送信したい場合は以下のようにします。

await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
    "Please confirm your account by: " + 
    HtmlEncoder.Default.Encode(callbackUrl).Replace("&amp;", "&"));

その際、その際クエリ文字列内の &amp; は & にしないと ConfirmEmail の OnGetAsync(string userId, string code) の code が null になってしまうので注意してください。

上記の結果、送信されたメールは以下の画像のようになります。(メーラーは Windows Live メールです)

送信されたメール

(8) RegisterConfirmation ページの修正

Areas/Identity/Pages/Account フォルダの RegisterConfirmation.cshtml.cs を開いて OnGetAsync メソッドを以下のように修正します。

RegisterConfirmation ページの修正

Email Confirmation を実装したので ConfirmationEmail ページへのリンクを表示する必要はありません。そのリンクを生成するコードをコメントアウトします。

加えて DisplayConfirmAccountLink を falses に設定し、ConfirmationEmail ページへのリンクではなくて単に "Please check your email to confirm your account." と表示されるようにします。

(9) Password Recovery

Password Recovery はユーザーがパスワードを忘れてしまっても復活できる手段を提供するものです。

上のステップ「(6) EmailSender クラスの実装」 まででメールは送信されるようになっていますので、基本的な機能だけなら既存のコードに手を加える必要はありません。

なお、スキャフォールディングで実装されるコードはメール送信機能を実装しないと Password Recovery が使えないコーディングになっていますので注意してください。(メール送信機能なしで Password Recovery を利用するにはコードを書き換える必要があります)

以下に Password Recovery がどのような動きになるかを説明しようと思いましたが、長くなりすぎるので別の記事「Password Recovery (CORE 版)」に書きました。興味があればそちらを見てください。

Tags: , , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar