ユーザー登録、電子メール確認、パスワード リセットを利用し、安全な ASP.NET Web フォームを作成する (C#)
作成者 : Erik Reitan
このチュートリアルでは、ASP.NET ID メンバーシップ システムを使用して、ユーザー登録、電子メールの確認、パスワードリセットを使用して ASP.NET Web Forms アプリを構築する方法について説明します。 このチュートリアルは、Rick Anderson の MVC チュートリアルに基づいていました。
はじめに
このチュートリアルでは、Visual Studio と ASP.NET 4.5 を使用して ASP.NET Web Forms アプリケーションを作成し、ユーザー登録、電子メール確認、パスワード リセットを使用してセキュリティで保護されたWeb Forms アプリを作成するために必要な手順について説明します。
チュートリアルのタスクと情報:
- ASP.NET Web Forms アプリを作成する
- SendGrid をフックする
- ログイン前Email確認が必要
- パスワードの回復とリセット
- 再送信Email確認リンク
- アプリのトラブルシューティング
- その他のリソース
ASP.NET Web Forms アプリを作成する
Note
警告: このチュートリアルを完了するには、Update 3 以降Visual Studio 2013インストールする必要があります。
新しいプロジェクト (ファイル ->新しいプロジェクト) を作成し、[新しいプロジェクト] ダイアログ ボックスから ASP.NET Web アプリケーション テンプレートと最新の.NET Frameworkバージョンを選択します。
[新しい ASP.NET プロジェクト] ダイアログ ボックスで、Web Forms テンプレートを選択します。 既定の認証は [個々のユーザー アカウント] のままにします。 Azure でアプリをホストする場合は、[クラウドでホストするチェック] チェック ボックスをオンのままにします。
次に、[ OK] を クリックして新しいプロジェクトを作成します。
プロジェクトの Secure Sockets Layer (SSL) を有効にします。 チュートリアル シリーズを使用したはじめにの「プロジェクトの SSL を有効にする」セクションWeb Forms記載されている手順に従います。
アプリを実行し、[ 登録 ] リンクをクリックして新しいユーザーを登録します。 この時点で、電子メールの検証は [EmailAddress] 属性に基づいてのみ、電子メール アドレスが整形式であることを確認します。 コードを変更して、電子メールの確認を追加します。 ブラウザー ウィンドウを閉じます。
[Server エクスプローラー of Visual Studio (View ->Server エクスプローラー)] で、Data Connections\DefaultConnection\Tables\AspNetUsers に移動し、右クリックして [テーブル定義を開く] を選択します。
次の図は、テーブル スキーマを
AspNetUsers
示しています。[サーバー エクスプローラー] で、AspNetUsers テーブルを右クリックし、[テーブル データの表示] を選択します。
この時点で、登録済みユーザーのメールは確認されていません。行をクリックし、[削除] を選択してユーザーを削除します。 次の手順でこのメールをもう一度追加し、確認メッセージをメール アドレスに送信します。
Email確認
新しいユーザーの登録中に電子メールを確認して、他のユーザーを偽装していないことを確認することをお勧めします (つまり、他のユーザーのメールに登録していません)。 ディスカッション フォーラムがあるとします。これは、 として"joe@contoso.com"
登録できないように"bob@cpandl.com"
したいとします。 電子メールの確認がない場合は、 "joe@contoso.com"
アプリから不要なメールを受け取る可能性があります。 Bob が誤って として "bib@cpandl.com"
登録され、それに気付かなかった場合、アプリに正しいメールがないため、パスワードの回復を使用できないとします。 Email確認では、ボットからの限定的な保護のみが提供され、決定されたスパマーからの保護は提供されません。
通常、新しいユーザーが電子メール、SMS テキスト メッセージ、または別のメカニズムによって確認される前に、Web サイトにデータを投稿できないようにする必要があります。 以下のセクションでは、電子メールの確認を有効にし、新しく登録されたユーザーがメールが確認されるまでログインできないようにコードを変更します。 このチュートリアルでは、メール サービス SendGrid を使用します。
SendGrid をフックする
SendGrid は、このチュートリアルが作成されて以来、API を変更しました。 現在の SendGrid の手順については、「 SendGrid 」または「 アカウントの確認とパスワードの回復を有効にする」を参照してください。
このチュートリアルでは SendGrid を介してメール通知を追加する方法のみを示していますが、SMTP やその他のメカニズムを使用してメールを送信できます ( その他のリソースを参照)。
Visual Studio で、パッケージ マネージャー コンソール (Tools -NuGet Package Manger ->>Package Manager Console) を開き、次のコマンドを入力します。
Install-Package SendGrid
Azure SendGrid サインアップ ページに移動し、無料の SendGrid アカウントに登録します。 SendGrid の サイトで無料の SendGrid アカウントに直接サインアップすることもできます。
ソリューション エクスプローラーから App_Startフォルダー内の IdentityConfig.cs ファイルを開き、SendGrid を構成するために黄色で強調表示された次の
EmailService
コードを クラスに追加します。public class EmailService : IIdentityMessageService { public async Task SendAsync(IdentityMessage message) { await configSendGridasync(message); } // Use NuGet to install SendGrid (Basic C# client lib) private async Task configSendGridasync(IdentityMessage message) { var myMessage = new SendGridMessage(); myMessage.AddTo(message.Destination); myMessage.From = new System.Net.Mail.MailAddress( "Royce@contoso.com", "Royce Sellars (Contoso Admin)"); myMessage.Subject = message.Subject; myMessage.Text = message.Body; myMessage.Html = message.Body; var credentials = new NetworkCredential( ConfigurationManager.AppSettings["emailServiceUserName"], ConfigurationManager.AppSettings["emailServicePassword"] ); // Create a Web transport for sending email. var transportWeb = new Web(credentials); // Send the email. if (transportWeb != null) { await transportWeb.DeliverAsync(myMessage); } else { Trace.TraceError("Failed to create Web transport."); await Task.FromResult(0); } } }
また、IdentityConfig.cs ファイルの先頭に次
using
のステートメントを追加します。using SendGrid; using System.Net; using System.Configuration; using System.Diagnostics;
このサンプルをシンプルにするために、メール サービス アカウントの値
appSettings
を web.config ファイルのセクションに格納します。 黄色で強調表示されている次の XML をプロジェクトのルートにある web.config ファイルに追加します。</connectionStrings> <appSettings> <add key="emailServiceUserName" value="[EmailServiceAccountUserName]" /> <add key="emailServicePassword" value="[EmailServiceAccountPassword]" /> </appSettings> <system.web>
警告
セキュリティ - 機密データをソース コードに格納しないでください。 この例では、アカウントと資格情報は、Web.config ファイルの appSetting セクションに格納されます。 Azure では、これらの値をAzure portalの [構成] タブに安全に格納できます。 関連情報については、「 パスワードやその他の機密データを ASP.NET および Azure にデプロイするためのベスト プラクティス」というタイトルの Rick Anderson のトピックを参照してください。
メール サービスの値を追加して、SendGrid 認証値 (ユーザー名とパスワード) を反映して、アプリからメールを正常に送信できるようにします。 SendGrid を指定したメール アドレスではなく、必ず SendGrid アカウント名を使用してください。
Email確認を有効にする
電子メールの確認を有効にするには、次の手順を使用して登録コードを変更します。
Account フォルダーで Register.aspx.cs コードビハインドを開き、 メソッドを
CreateUser_Click
更新して、次の強調表示された変更を有効にします。protected void CreateUser_Click(object sender, EventArgs e) { var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>(); var user = new ApplicationUser() { UserName = Email.Text, Email = Email.Text }; IdentityResult result = manager.Create(user, Password.Text); if (result.Succeeded) { // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771 string code = manager.GenerateEmailConfirmationToken(user.Id); string callbackUrl = IdentityHelper.GetUserConfirmationRedirectUrl(code, user.Id, Request); manager.SendEmail(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>."); IdentityHelper.SignIn(manager, user, isPersistent: false); IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response); } else { ErrorMessage.Text = result.Errors.FirstOrDefault(); } }
ソリューション エクスプローラーで Default.aspx を右クリックし、[スタート ページとして設定] を選択します。
F5 キーを押してアプリを実行します。ページが表示されたら、[登録] リンクをクリックして [登録] ページを表示します。
メールとパスワードを入力し、[ 登録 ] ボタンをクリックして SendGrid 経由で電子メール メッセージを送信します。
プロジェクトとコードの現在の状態では、ユーザーがアカウントを確認していない場合でも、登録フォームを完了するとログインできるようになります。メール アカウントを確認し、リンクをクリックしてメールを確認します。
登録フォームを送信すると、ログインします。
ログイン前Email確認が必要
メール アカウントを確認しましたが、この時点で、確認メールに含まれているリンクをクリックして完全にサインインする必要はありません。 次のセクションでは、新しいユーザーがログイン (認証) される前に確認済みの電子メールを受け取る必要があるコードを変更します。
Visual Studio ソリューション エクスプローラーで、Accounts フォルダーに含まれる Register.aspx.cs コードビハインドのイベントを、次の強調表示された変更で更新
CreateUser_Click
します。protected void CreateUser_Click(object sender, EventArgs e) { var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>(); var user = new ApplicationUser() { UserName = Email.Text, Email = Email.Text }; IdentityResult result = manager.Create(user, Password.Text); if (result.Succeeded) { // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771 string code = manager.GenerateEmailConfirmationToken(user.Id); string callbackUrl = IdentityHelper.GetUserConfirmationRedirectUrl(code, user.Id, Request); manager.SendEmail(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>."); if (user.EmailConfirmed) { IdentityHelper.SignIn(manager, user, isPersistent: false); IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response); } else { ErrorMessage.Text = "An email has been sent to your account. Please view the email and confirm your account to complete the registration process."; } } else { ErrorMessage.Text = result.Errors.FirstOrDefault(); } }
LogIn
Login.aspx.cs コードビハインドの メソッドを、次の強調表示された変更で更新します。protected void LogIn(object sender, EventArgs e) { if (IsValid) { // Validate the user password var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>(); var signinManager = Context.GetOwinContext().GetUserManager<ApplicationSignInManager>(); // Require the user to have a confirmed email before they can log on. var user = manager.FindByName(Email.Text); if (user != null) { if (!user.EmailConfirmed) { FailureText.Text = "Invalid login attempt. You must have a confirmed email account."; ErrorMessage.Visible = true; } else { // This doen't count login failures towards account lockout // To enable password failures to trigger lockout, change to shouldLockout: true var result = signinManager.PasswordSignIn(Email.Text, Password.Text, RememberMe.Checked, shouldLockout: false); switch (result) { case SignInStatus.Success: IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response); break; case SignInStatus.LockedOut: Response.Redirect("/Account/Lockout"); break; case SignInStatus.RequiresVerification: Response.Redirect(String.Format("/Account/TwoFactorAuthenticationSignIn?ReturnUrl={0}&RememberMe={1}", Request.QueryString["ReturnUrl"], RememberMe.Checked), true); break; case SignInStatus.Failure: default: FailureText.Text = "Invalid login attempt"; ErrorMessage.Visible = true; break; } } } } }
アプリケーションの実行
ユーザーのメール アドレスが確認されたかどうかをチェックするコードを実装したので、[登録] ページと [ログイン] ページの両方で機能をチェックできます。
- テストする電子メール エイリアスを含む AspNetUsers テーブル内のすべてのアカウントを削除します。
- アプリ (F5) を実行し、メール アドレスを確認するまでユーザーとして登録できないことを確認します。
- 送信されたメールで新しいアカウントを確認する前に、新しいアカウントでログインを試みます。
ログインできず、確認済みのメール アカウントが必要であることがわかります。 - メール アドレスを確認したら、アプリにログインします。
パスワードの回復とリセット
Visual Studio で、Account フォルダーに含まれる Forgot.aspx.cs コードビハインドのメソッドから
Forgot
コメント文字を削除し、メソッドが次のように表示されるようにします。protected void Forgot(object sender, EventArgs e) { if (IsValid) { // Validate the user's email address var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>(); ApplicationUser user = manager.FindByName(Email.Text); if (user == null || !manager.IsEmailConfirmed(user.Id)) { FailureText.Text = "The user either does not exist or is not confirmed."; ErrorMessage.Visible = true; return; } // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771 // Send email with the code and the redirect to reset password page string code = manager.GeneratePasswordResetToken(user.Id); string callbackUrl = IdentityHelper.GetResetPasswordRedirectUrl(code, Request); manager.SendEmail(user.Id, "Reset Password", "Please reset your password by clicking <a href=\"" + callbackUrl + "\">here</a>."); loginForm.Visible = false; DisplayEmail.Visible = true; } }
Login.aspx ページを開きます。 次に強調表示されているように、 loginForm セクションの末尾付近にあるマークアップを置き換えます。
<%@ Page Title="Log in" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="WebForms002.Account.Login" Async="true" %> <%@ Register Src="~/Account/OpenAuthProviders.ascx" TagPrefix="uc" TagName="OpenAuthProviders" %> <asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent"> <h2><%: Title %>.</h2> <div class="row"> <div class="col-md-8"> <section id="loginForm"> <div class="form-horizontal"> <h4>Use a local account to log in.</h4> <hr /> <asp:PlaceHolder runat="server" ID="ErrorMessage" Visible="false"> <p class="text-danger"> <asp:Literal runat="server" ID="FailureText" /> </p> </asp:PlaceHolder> <div class="form-group"> <asp:Label runat="server" AssociatedControlID="Email" CssClass="col-md-2 control-label">Email</asp:Label> <div class="col-md-10"> <asp:TextBox runat="server" ID="Email" CssClass="form-control" TextMode="Email" /> <asp:RequiredFieldValidator runat="server" ControlToValidate="Email" CssClass="text-danger" ErrorMessage="The email field is required." /> </div> </div> <div class="form-group"> <asp:Label runat="server" AssociatedControlID="Password" CssClass="col-md-2 control-label">Password</asp:Label> <div class="col-md-10"> <asp:TextBox runat="server" ID="Password" TextMode="Password" CssClass="form-control" /> <asp:RequiredFieldValidator runat="server" ControlToValidate="Password" CssClass="text-danger" ErrorMessage="The password field is required." /> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <div class="checkbox"> <asp:CheckBox runat="server" ID="RememberMe" /> <asp:Label runat="server" AssociatedControlID="RememberMe">Remember me?</asp:Label> </div> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <asp:Button runat="server" OnClick="LogIn" Text="Log in" CssClass="btn btn-default" /> </div> </div> </div> <p> <asp:HyperLink runat="server" ID="RegisterHyperLink" ViewStateMode="Disabled">Register as a new user</asp:HyperLink> </p> <p> <%-- Enable this once you have account confirmation enabled for password reset functionality --%> <asp:HyperLink runat="server" ID="ForgotPasswordHyperLink" ViewStateMode="Disabled">Forgot your password?</asp:HyperLink> </p> </section> </div> <div class="col-md-4"> <section id="socialLoginForm"> <uc:OpenAuthProviders runat="server" ID="OpenAuthLogin" /> </section> </div> </div> </asp:Content>
Login.aspx.cs 分離コードを開き、イベント ハンドラーから黄色で強調表示された次のコード行のコメントを
Page_Load
解除します。protected void Page_Load(object sender, EventArgs e) { RegisterHyperLink.NavigateUrl = "Register"; // Enable this once you have account confirmation enabled for password reset functionality ForgotPasswordHyperLink.NavigateUrl = "Forgot"; OpenAuthLogin.ReturnUrl = Request.QueryString["ReturnUrl"]; var returnUrl = HttpUtility.UrlEncode(Request.QueryString["ReturnUrl"]); if (!String.IsNullOrEmpty(returnUrl)) { RegisterHyperLink.NavigateUrl += "?ReturnUrl=" + returnUrl; } }
F5 キーを押してアプリを実行します。ページが表示されたら、[ログイン] リンクをクリックします。
[ パスワードを忘れた場合] リンクをクリックして、[ パスワードを忘れた場合 ] ページを表示します。
メール アドレスを入力し、[ 送信 ] ボタンをクリックして、パスワードをリセットできるメールをアドレスに送信します。
メール アカウントを確認し、リンクをクリックして [パスワードのリセット ] ページを表示します。[ パスワードのリセット ] ページで、メール、パスワード、確認済みパスワードを入力します。 次に、[ リセット ] ボタンを押します。
パスワードを正常にリセットすると、[ パスワードの変更 ] ページが表示されます。 これで、新しいパスワードでログインできます。
再送信Email確認リンク
ユーザーが新しいローカル アカウントを作成すると、ログオンする前に使用する必要がある確認リンクが電子メールで送信されます。 ユーザーが誤って確認メールを削除した場合、または電子メールが届かなかった場合は、もう一度確認リンクを送信する必要があります。 次のコード変更は、これを有効にする方法を示しています。
Visual Studio で Login.aspx.cs 分離コードを開き、イベント ハンドラーの後に次のイベント ハンドラーを
LogIn
追加します。protected void SendEmailConfirmationToken(object sender, EventArgs e) { var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>(); var user = manager.FindByName(Email.Text); if (user != null) { if (!user.EmailConfirmed) { string code = manager.GenerateEmailConfirmationToken(user.Id); string callbackUrl = IdentityHelper.GetUserConfirmationRedirectUrl(code, user.Id, Request); manager.SendEmail(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>."); FailureText.Text = "Confirmation email sent. Please view the email and confirm your account."; ErrorMessage.Visible = true; ResendConfirm.Visible = false; } } }
LogIn
次のように黄色で強調表示されたコードを変更して、Login.aspx.cs 分離コードのイベント ハンドラーを変更します。protected void LogIn(object sender, EventArgs e) { if (IsValid) { // Validate the user password var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>(); var signinManager = Context.GetOwinContext().GetUserManager<ApplicationSignInManager>(); // Require the user to have a confirmed email before they can log on. var user = manager.FindByName(Email.Text); if (user != null) { if (!user.EmailConfirmed) { FailureText.Text = "Invalid login attempt. You must have a confirmed email address. Enter your email and password, then press 'Resend Confirmation'."; ErrorMessage.Visible = true; ResendConfirm.Visible = true; } else { // This doen't count login failures towards account lockout // To enable password failures to trigger lockout, change to shouldLockout: true var result = signinManager.PasswordSignIn(Email.Text, Password.Text, RememberMe.Checked, shouldLockout: false); switch (result) { case SignInStatus.Success: IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response); break; case SignInStatus.LockedOut: Response.Redirect("/Account/Lockout"); break; case SignInStatus.RequiresVerification: Response.Redirect(String.Format("/Account/TwoFactorAuthenticationSignIn?ReturnUrl={0}&RememberMe={1}", Request.QueryString["ReturnUrl"], RememberMe.Checked), true); break; case SignInStatus.Failure: default: FailureText.Text = "Invalid login attempt"; ErrorMessage.Visible = true; break; } } } } }
次のように黄色で強調表示されたコードを追加して 、Login.aspx ページを更新します。
<%@ Page Title="Log in" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="WebForms002.Account.Login" Async="true" %> <%@ Register Src="~/Account/OpenAuthProviders.ascx" TagPrefix="uc" TagName="OpenAuthProviders" %> <asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent"> <h2><%: Title %>.</h2> <div class="row"> <div class="col-md-8"> <section id="loginForm"> <div class="form-horizontal"> <h4>Use a local account to log in.</h4> <hr /> <asp:PlaceHolder runat="server" ID="ErrorMessage" Visible="false"> <p class="text-danger"> <asp:Literal runat="server" ID="FailureText" /> </p> </asp:PlaceHolder> <div class="form-group"> <asp:Label runat="server" AssociatedControlID="Email" CssClass="col-md-2 control-label">Email</asp:Label> <div class="col-md-10"> <asp:TextBox runat="server" ID="Email" CssClass="form-control" TextMode="Email" /> <asp:RequiredFieldValidator runat="server" ControlToValidate="Email" CssClass="text-danger" ErrorMessage="The email field is required." /> </div> </div> <div class="form-group"> <asp:Label runat="server" AssociatedControlID="Password" CssClass="col-md-2 control-label">Password</asp:Label> <div class="col-md-10"> <asp:TextBox runat="server" ID="Password" TextMode="Password" CssClass="form-control" /> <asp:RequiredFieldValidator runat="server" ControlToValidate="Password" CssClass="text-danger" ErrorMessage="The password field is required." /> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <div class="checkbox"> <asp:CheckBox runat="server" ID="RememberMe" /> <asp:Label runat="server" AssociatedControlID="RememberMe">Remember me?</asp:Label> </div> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <asp:Button runat="server" OnClick="LogIn" Text="Log in" CssClass="btn btn-default" /> <asp:Button runat="server" ID="ResendConfirm" OnClick="SendEmailConfirmationToken" Text="Resend confirmation" Visible="false" CssClass="btn btn-default" /> </div> </div> </div> <p> <asp:HyperLink runat="server" ID="RegisterHyperLink" ViewStateMode="Disabled">Register as a new user</asp:HyperLink> </p> <p> <%-- Enable this once you have account confirmation enabled for password reset functionality --%> <asp:HyperLink runat="server" ID="ForgotPasswordHyperLink" ViewStateMode="Disabled">Forgot your password?</asp:HyperLink> </p> </section> </div> <div class="col-md-4"> <section id="socialLoginForm"> <uc:OpenAuthProviders runat="server" ID="OpenAuthLogin" /> </section> </div> </div> </asp:Content>
テストする電子メール エイリアスを含む AspNetUsers テーブル内のすべてのアカウントを削除します。
アプリ (F5) を実行し、メール アドレスを登録します。
送信したばかりのメールで新しいアカウントを確認する前に、新しいアカウントでログインを試みます。
ログインできず、確認済みのメール アカウントが必要であることがわかります。 さらに、確認メッセージをメール アカウントに再送信できるようになりました。メール アドレスとパスワードを入力し、[再送信] 確認 ボタンを押します。
新しく送信されたメール メッセージに基づいてメール アドレスを確認したら、アプリにログインします。
アプリのトラブルシューティング
資格情報を確認するためのリンクを含む電子メールが届かない場合:
- 迷惑メール フォルダーまたはスパム フォルダーを確認します。
- SendGrid アカウントにログインし、[Email アクティビティ] リンクをクリックします。
- SendGrid アカウントのメール アドレスではなく、 SendGrid ユーザー アカウント名をWeb.config値として使用したとします。
その他のリソース
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示