具有 SMS 和电子邮件双因素身份验证的 ASP.NET MVC 5 应用

作者 :Rick Anderson

本教程介绍如何使用 Two-Factor 身份验证生成 ASP.NET MVC 5 Web 应用。 在继续操作之前,应完成创建 具有登录、电子邮件确认和密码重置的安全 ASP.NET MVC 5 Web 应用 。 可以 在此处下载已完成的应用程序。 下载包含调试帮助程序,让你无需设置电子邮件或短信提供程序即可测试电子邮件确认和短信。

本教程由 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 Forms还支持 ASP.NET 标识,因此你可以在 Web 窗体应用中执行类似的步骤。
    显示“新建 AS P 点 NET 项目”窗口的屏幕截图。突出显示了默认身份验证“个人用户帐户”。
  2. 将默认身份验证保留为 “个人用户帐户”。 如果要在 Azure 中托管应用,请将“检查”框保留为选中。 在本教程的后面部分,我们将部署到 Azure。 可以 免费打开 Azure 帐户
  3. 项目设置为使用 SSL

为双因素身份验证设置短信

本教程提供有关使用 Twilio 或 ASPSMS 的说明,但你可以使用任何其他 SMS 提供程序。

  1. 使用 SMS 提供程序创建用户帐户

    创建 TwilioASPSMS 帐户。

  2. 安装其他包或添加服务引用

    Twilio:
    在“包管理器控制台”中,输入以下命令:
    Install-Package Twilio

    ASPSMS:
    需要添加以下服务引用:

    显示“添加服务引用”窗口的屏幕截图。突出显示了“地址”和“命名空间”输入栏。

    地址:
    https://webservice.aspsms.com/aspsmsx2.asmx?WSDL

    命名空间:
    ASPSMSX2

  3. 找出 SMS 提供程序用户凭据

    Twilio:
    从 Twilio 帐户的“ 仪表板 ”选项卡中,复制 帐户 SID身份验证令牌

    ASPSMS:
    在帐户设置中,导航到 “Userkey” ,并将其与自定义 密码一起复制。

    稍后,我们会将这些值存储在键 "SMSAccountIdentification""SMSAccountPassword" 内的 web.config 文件中。

  4. 指定 SenderID/发信方

    Twilio:
    从“ 号码 ”选项卡中,复制 Twilio 电话号码。

    ASPSMS:
    在“ 解锁发起方 ”菜单中,解锁一个或多个发起方或选择字母数字发起方 (并非所有网络) 都支持。

    稍后,我们将此值存储在键 "SMSAccountFrom" 内的 web.config 文件中。

  5. 将 SMS 提供程序凭据传输到应用中

    使凭据和发件人电话号码可供应用使用。 为简单起见,我们会将这些值存储在 web.config 文件中。 部署到 Azure 时,可以将值安全地存储在网站“配置”选项卡上的“ 应用设置 ”部分中。

    </connectionStrings>
       <appSettings>
          <add key="webpages:Version" value="3.0.0.0" />
          <!-- Markup removed for clarity. -->
          <!-- SendGrid-->
          <add key="mailAccount" value="account" />
          <add key="mailPassword" value="password" />
          <add key="SMSAccountIdentification" value="My Identification" />
          <add key="SMSAccountPassword" value="My Password" />
          <add key="SMSAccountFrom" value="+12065551234" />
       </appSettings>
      <system.web>
    

    警告

    安全性 - 切勿将敏感数据存储在源代码中。 将帐户和凭据添加到上面的代码中,使示例保持简单。 请参阅 将密码和其他敏感数据部署到 ASP.NET 和 Azure 的最佳做法

  6. 实现到 SMS 提供程序的数据传输

    SmsServiceApp_Start\IdentityConfig.cs 文件中配置 类。

    根据使用的 SMS 提供程序激活 TwilioASPSMS 部分:

    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
        }
    }
    
  7. 更新 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>
    
  8. 验证 中的 EnableTwoFactorAuthentication 和 操作方法是否具有[ValidateAntiForgeryToken] 属性:DisableTwoFactorAuthenticationManageController

    //
    // 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");
    }
    
  9. 运行应用并使用之前注册的帐户登录。

  10. 单击“用户 ID”,这将激活控制器中的IndexManage操作方法。
    显示 A S P dot NET 应用主页的屏幕截图。突出显示了“示例用户 ID”。

  11. 单击“添加”。
    显示“A S P dot NET 应用帐户设置”页的屏幕截图。突出显示了“电话号码”部分旁边的“无添加”。

  12. 操作 AddPhoneNumber 方法显示一个对话框,用于输入可以接收短信的电话号码。

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

    显示“A S P dot NET 应用添加电话号码”页的屏幕截图。示例电话号码在下方填写“发送验证码”按钮。

  13. 几秒钟后,你将收到一条包含验证码的短信。 输入并按 “提交”。
    A S P dot NET 应用“添加电话号码”页的屏幕截图,其中显示了一个输入栏,其中填充了示例验证码,下方有一个“提交”按钮。

  14. “管理”视图显示已添加电话号码。

启用双因素身份验证

在模板生成的应用中,需要使用 UI 启用双因素身份验证 (2FA) 。 若要启用 2FA,请单击导航栏中的用户 ID (电子邮件别名) 。

显示 A S P dot NET 应用主页的屏幕截图。突出显示了示例用户 ID。

单击“启用 2FA”。

显示“A S P dot NET 应用帐户设置”页的屏幕截图。Two-Factor身份验证:已禁用,其中突出显示了“启用链接”部分。

注销,然后重新登录。 如果已启用电子邮件 (请参阅上一 篇教程) ,则可以为 2FA 选择短信或电子邮件。

显示“A S P dot NET 应用发送验证码”页的屏幕截图。显示“电话号码”和“Email代码”处于选中状态的下拉菜单。

将显示“验证代码”页,可在其中输入来自短信或电子邮件) 的代码 (。

显示 2 个 FA 的 A S P dot NET 应用的“验证”页的屏幕截图。在示例代码下面,突出显示了“记住此浏览器”的复选框。

单击“记住此浏览器检查”框将免除在使用选中该框的浏览器和设备时使用 2FA 登录的需要。 只要恶意用户无法访问你的设备,启用 2FA 并单击“ 记住此浏览器 ”即可为你提供方便的一步密码访问,同时仍保留对来自不受信任设备的所有访问的强 2FA 保护。 可以在经常使用的任何专用设备上进行此操作。

本教程简要介绍了如何在新的 ASP.NET MVC 应用上启用 2FA。 我的教程 将短信和电子邮件与 ASP.NET Identity 结合使用双因素身份验证 详细介绍了示例背后的代码。

其他资源