次の方法で共有


ASP.NET MVC 5 アプリで SMS と電子メール Two-Factor 認証を使用する

作成者: Rick Anderson

このチュートリアルでは、2 要素認証を使用して ASP.NET MVC 5 Web アプリを構築する方法について説明します。 続行する前に、「ログイン、電子メール確認、パスワード リセットを使用して安全な ASP.NET MVC 5 Web アプリを作成する」を完了する必要があります。 完成したアプリケーションはこちらからダウンロードできます。 ダウンロードには、電子メールまたは SMS プロバイダーを設定せずに電子メールの確認と SMS をテストできるデバッグ ヘルパーが含まれています。

このチュートリアルは Rick Anderson (Twitter: @RickAndMSFT) によって作成されました。

ASP.NET MVC アプリを作成する

まず、Visual Studio Express 2013 for Web 以降をインストールして実行します。

メモ

警告: 続行する前に、「ログイン、電子メール確認、パスワード リセットを使用して安全な ASP.NET MVC 5 Web アプリを作成する」を完了する必要があります。 このチュートリアルを完了するには、Visual Studio 2013 Update 3 以降をインストールする必要があります。

  1. 新しい ASP.NET Web プロジェクトを作成し、MVC テンプレートを選択します。 Web フォームでは ASP.NET ID もサポートされているため、Web フォーム アプリでも同様の手順を実行できます。
    [新しい ASP.NET プロジェクト] ウィンドウが表示されているスクリーンショット。デフォルトの認証である [個人ユーザー アカウント] が強調表示されています。
  2. 既定の認証は [個人ユーザー アカウント] のままにします。 Azure でアプリをホストする場合は、チェック ボックスをオンのままにします。 チュートリアルの後半で Azure にデプロイします。 Azure アカウントの開設は無料です
  3. SSL を使用するようにプロジェクトを設定します。

2 要素認証用に SMS を設定する

このチュートリアルでは、Twilio または ASPSMS を使用する手順を説明しますが、他の SMS プロバイダーも使用できます。

  1. SMS プロバイダーを使用したユーザー アカウントの作成

    Twilio または ASPSMS のアカウントを作成します。

  2. 追加パッケージのインストールまたはサービス参照の追加

    Twilio:
    パッケージ マネージャー コンソールで、次のコマンドを入力します。
    Install-Package Twilio

    ASPSMS:
    次のサービス参照を追加する必要があります。

    [サービス参照の追加] ウィンドウが表示されているスクリーンショット。[アドレス] と [名前空間] の入力バーが強調表示されています。

    Address:
    https://webservice.aspsms.com/aspsmsx2.asmx?WSDL

    名前空間:
    ASPSMSX2

  3. SMS プロバイダーのユーザー資格情報の把握

最も安全な認証オプションを使用することをお勧めします。 Azure にデプロイされた .NET アプリについては、次を参照してください。

Azure Key Vault と .NET Aspire は、シークレットを格納および取得するための最も安全な方法を提供します。 Azure Key Vault は、暗号化キーとシークレット (証明書、接続文字列、パスワードなど) を保護するクラウド サービスです。 .NET アスパイアについては、「ホスティングとクライアント統合の間のセキュリティで保護された通信を参照してください。

リソース所有者のパスワード資格情報の付与は、次の理由で回避してください。

  • ユーザーのパスワードをクライアントに公開します。
  • これは重大なセキュリティ上のリスクです。
  • 他の認証フローが不可能な場合にのみ使用してください。

アプリがテスト サーバーにデプロイされると、環境変数を使用して接続文字列をテスト データベース サーバーに設定できます。 環境変数は、通常、暗号化されていないプレーンテキストで格納されます。 コンピューターまたはプロセスが侵害された場合、信頼されていないパーティーが環境変数にアクセスできるようになります。 最も安全な方法ではないため、環境変数を使用して本番接続文字列を格納しないことをお勧めします。

構成データのガイドライン:

  • 構成プロバイダーのコードやプレーンテキストの構成ファイルには、パスワードなどの機密データを格納しないでください。
  • 開発環境やテスト環境では運用シークレットを使用しないでください。
  • プロジェクトの外部にシークレットを指定してください。そうすれば、誤ってリソース コード リポジトリにコミットされることはありません。

Twilio:
Twilio アカウントの [ダッシュボード] タブで、アカウント SID をコピーし、認証トークンをコピーします。

ASPSMS:
アカウント設定から [Userkey] に移動し、自分で定義したパスワードと一緒にコピーします。

これらの値は、後でキー "SMSAccountIdentification" および "SMSAccountPassword" 内の web.config ファイルに格納します。 4. 送信者ID/起点を指定する

Twilio:
[番号] タブで Twilio の電話番号をコピーします。

ASPSMS:
[発信元のロック解除] メニューで、1 つ以上の発信元のロックを解除するか、英数字の発信元を選択します (すべてのネットワークでサポートされているわけではありません)。

この値は、後でキー "SMSAccountFrom" 内の web.config ファイルに格納します。 5. SMS プロバイダーの資格情報をアプリ に転送する

アプリで資格情報と送信者の電話番号を使用できるようにします。 わかりやすくするために、これらの値を web.config ファイルに格納します。 Azure にデプロイする際に、Web サイトの構成タブのアプリ設定セクションに値を安全に格納できます。

[!code-xml[Main](aspnet-mvc-5-app-with-sms-and-email-two-factor-authentication/samples/sample1.xml?highlight=8-10)]

> [!WARNING]
> Security - Never store sensitive data in your source code. The account and credentials are added to the code above to keep the sample simple. See [Best practices for deploying passwords and other sensitive data to ASP.NET and Azure](../../../identity/overview/features-api/best-practices-for-deploying-passwords-and-other-sensitive-data-to-aspnet-and-azure.md).
  1. SMS プロバイダーへのデータ転送の実装

    App_Start\IdentityConfig.cs ファイルで SmsService クラスを構成します。

    使用される SMS プロバイダーに応じて、[Twilio] または [ASPSMS] セクションをアクティブ化します。

    public class SmsService : IIdentityMessageService
    {
        public Task SendAsync(IdentityMessage message)
        {
            // Twilio Begin
            //var accountSid = ConfigurationManager.AppSettings["SMSAccountIdentification"];
            //var authToken = ConfigurationManager.AppSettings["SMSAccountPassword"];
            //var fromNumber = ConfigurationManager.AppSettings["SMSAccountFrom"];
    
            //TwilioClient.Init(accountSid, authToken);
    
            //MessageResource result = MessageResource.Create(
                //new PhoneNumber(message.Destination),
                //from: new PhoneNumber(fromNumber),
               //body: message.Body
            //);
    
            ////Status is one of Queued, Sending, Sent, Failed or null if the number is not valid
             //Trace.TraceInformation(result.Status.ToString());
            ////Twilio doesn't currently have an async API, so return success.
             //return Task.FromResult(0);    
            // Twilio End
    
            // ASPSMS Begin 
            // var soapSms = new MvcPWx.ASPSMSX2.ASPSMSX2SoapClient("ASPSMSX2Soap");
            // soapSms.SendSimpleTextSMS(
            //   System.Configuration.ConfigurationManager.AppSettings["SMSAccountIdentification"],
            //   System.Configuration.ConfigurationManager.AppSettings["SMSAccountPassword"],
            //   message.Destination,
            //   System.Configuration.ConfigurationManager.AppSettings["SMSAccountFrom"],
            //   message.Body);
            // soapSms.Close();
            // return Task.FromResult(0);
            // ASPSMS End
        }
    }
    
  2. Views\Manage\Index.cshtml Razor ビューを更新します (注: 終了コードのコメントを削除するだけでなく、次のコードを使用してください)。

    @model MvcPWy.Models.IndexViewModel
    @{
       ViewBag.Title = "Manage";
    }
    <h2>@ViewBag.Title.</h2>
    <p class="text-success">@ViewBag.StatusMessage</p>
    <div>
       <h4>Change your account settings</h4>
       <hr />
       <dl class="dl-horizontal">
          <dt>Password:</dt>
          <dd>
             [
             @if (Model.HasPassword)
             {
                @Html.ActionLink("Change your password", "ChangePassword")
             }
             else
             {
                @Html.ActionLink("Create", "SetPassword")
             }
             ]
          </dd>
          <dt>External Logins:</dt>
          <dd>
             @Model.Logins.Count [
             @Html.ActionLink("Manage", "ManageLogins") ]
          </dd>
            <dt>Phone Number:</dt>
          <dd>
             @(Model.PhoneNumber ?? "None") [
             @if (Model.PhoneNumber != null)
             {
                @Html.ActionLink("Change", "AddPhoneNumber")
                @: &nbsp;|&nbsp;
                @Html.ActionLink("Remove", "RemovePhoneNumber")
             }
             else
             {
                @Html.ActionLink("Add", "AddPhoneNumber")
             }
             ]
          </dd>
          <dt>Two-Factor Authentication:</dt> 
          <dd>
             @if (Model.TwoFactor)
             {
                using (Html.BeginForm("DisableTwoFactorAuthentication", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
                {
                   @Html.AntiForgeryToken()
                   <text>Enabled
                      <input type="submit" value="Disable" class="btn btn-link" />
                   </text>
                }
             }
             else
             {
                using (Html.BeginForm("EnableTwoFactorAuthentication", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
                {
                   @Html.AntiForgeryToken()
                   <text>Disabled
                      <input type="submit" value="Enable" class="btn btn-link" />
                   </text>
                }
             }
          </dd>
       </dl>
    </div>
    
  3. ManageControllerEnableTwoFactorAuthentication および DisableTwoFactorAuthentication アクション メソッドに [ValidateAntiForgeryToken] 属性があることを確認します。

    //
    // POST: /Manage/EnableTwoFactorAuthentication
    [HttpPost,ValidateAntiForgeryToken]
    public async Task<ActionResult> EnableTwoFactorAuthentication()
    {
        await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
        var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if (user != null)
        {
            await SignInAsync(user, isPersistent: false);
        }
        return RedirectToAction("Index", "Manage");
    }
    //
    // POST: /Manage/DisableTwoFactorAuthentication
    [HttpPost, ValidateAntiForgeryToken]
    public async Task<ActionResult> DisableTwoFactorAuthentication()
    {
        await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), false);
        var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if (user != null)
        {
            await SignInAsync(user, isPersistent: false);
        }
        return RedirectToAction("Index", "Manage");
    }
    
  4. アプリを実行し、以前に登録したアカウントでログインします。

  5. ユーザー ID をクリックすると、Index コントローラー内の Manage アクション メソッドがアクティブになります。
    ASP.NET アプリのホーム ページが表示されているスクリーンショット。サンプル ユーザー ID が強調表示されています。

  6. [追加] をクリックします。
    ASP. NET アプリの [アカウント設定] ページが表示されているスクリーンショット。[電話番号] セクションの横の [追加なし] が強調表示されています。

  7. AddPhoneNumber アクション メソッドは、SMS メッセージを受信できる電話番号を入力するダイアログ ボックスを表示します。

    // GET: /Account/AddPhoneNumber
    public ActionResult AddPhoneNumber()
    {
       return View();
    }
    

    ASP.NET アプリの [電話番号の追加] ページが表示されているスクリーンショット。サンプルの電話番号が入力されており、その下に [確認コードの送信] ボタンがあります。

  8. 数秒後に、確認コードを含むテキスト メッセージが届きます。 それを入力し、「送信」を押します
    ASP.NET アプリの [電話番号の追加] ページのスクリーンショットで、サンプルの確認コードが入力されている入力バーがあり、その下に [送信] ボタンがあります。

  9. [管理] ビューには電話番号が追加されたことが表示されます。

2 要素認証を有効にする

テンプレートで生成されたアプリでは、UI を使用して 2 要素認証 (2FA) を有効にする必要があります。 2FA を有効にするには、ナビゲーション バーでユーザー ID (電子メール エイリアス) をクリックします。

ASP.NET アプリのホーム ページが表示されているスクリーンショット。サンプル ユーザー ID が強調表示されています。

[2FA を有効にする] をクリックします。

ASP.NET アプリの [アカウント設定] ページが表示されているスクリーンショット。2 要素認証が無効になっており、[リンクの有効化] セクションが強調表示されています。

ログアウトしてからもう一度ログインします。 電子メールを有効にしている場合 (前のチュートリアルを参照)、2FA 用の SMS または電子メールを選択できます。

ASP.NET アプリの [確認コードの送信] ページが表示されているスクリーンショット。[電話コード] と [電子メール コード] を示すドロップダウン メニューが選択されています。

[コードの確認] ページが表示され、ここで (SMS または電子メールに記載されている) コードを入力できます。

2FA 用の ASP.NET アプリの [確認] ページが表示されているスクリーンショット。サンプル コードの下で、[このブラウザーを記憶する] チェックボックスが強調表示されています。

[このブラウザーを記憶する] チェックボックスをオンにすると、このチェックボックスがオンになっているブラウザーとデバイスでは、2FA を使用せずにログインできます。 悪意のあるユーザーがデバイスにアクセスできない限り、2FA を有効にし、このブラウザーを記憶する をクリックすることで、信頼されていないデバイスからのすべてのアクセスに対して強力な 2FA 保護を維持しつつ、便利なワンステップパスワードアクセスを提供します。 これは、定期的に使用するすべてのプライベート デバイスで実行できます。

このチュートリアルでは、新しい ASP.NET MVC アプリで 2FA を有効にする方法について簡単に説明します。 私のチュートリアル「ASP.NET Identity で SMS と電子メールを利用して 2 要素認証を行う」では、サンプルの背後にあるコードについて詳しく説明しています。

その他のリソース