使用短信 Two-Factor 身份验证创建 ASP.NET Web 窗体应用(C#)

作者:Erik Reitan

本教程介绍如何使用 Two-Factor 身份验证生成 ASP.NET Web 窗体应用。 本教程的设计旨在作为补充,补充标题为创建具有用户注册、电子邮件确认和密码重置功能的安全 ASP.NET Web 窗体应用的教程。 此外,本教程是基于 Rick Anderson 的 MVC 教程

介绍

本教程指导你完成创建支持使用 Visual Studio 进行 Two-Factor 身份验证的 ASP.NET Web 窗体应用程序所需的步骤。 Two-Factor 身份验证是额外的用户身份验证步骤。 此额外步骤在登录期间生成唯一的个人标识号(PIN)。 PIN 通常以电子邮件或短信的形式发送给用户。 然后,应用的用户在登录时输入 PIN 作为额外的身份验证度量值。

教程任务和信息:

创建 ASP.NET Web 窗体应用

首先安装和运行 Visual Studio Express 2013 for WebVisual Studio 2013。 安装 Visual Studio 2013 Update 3 或更高版本。 此外,还需要创建 Twilio 帐户,如下所示。

注意

重要说明:必须安装 Visual Studio 2013 Update 3 或更高版本才能完成本教程。

  1. 创建新项目(文件 ->新建项目),并从“新建项目”对话框中选择 ASP.NET Web 应用程序 模板以及 .NET Framework 版本 4.5.2。
  2. “新建 ASP.NET 项目”对话框中,选择 Web 表单 模板。 将默认身份验证保留为 单个用户帐户。 然后,单击确定以创建新项目。
    新建 ASP 点网络项目”对话框的屏幕截图,其中以蓝色突出显示了 Web 窗体图标。
  3. 为项目启用安全套接字层(SSL)。 请按照 Web 窗体入门教程系列为项目启用 SSL 一节中的步骤进行操作。
  4. 在 Visual Studio 中,打开 包管理器控制台工具 ->NuGet 包管理器 ->包管理器控制台),并输入以下命令:
    Install-Package Twilio

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

本教程使用 Twilio,但你可以使用任何 SMS 提供程序。

  1. 创建 Twilio 帐户。

  2. 从 Twilio 帐户的“仪表板”选项卡中,复制 帐户 SID身份验证令牌。 稍后将将它们添加到应用。

  3. 号码选项卡中,同样复制 Twilio 电话号码

  4. 将 Twilio 帐户 SID身份验证令牌电话号码 提供给应用。 为简单起见,请将这些值存储在 web.config 文件中。 部署到 Azure 时,可以在“网站配置”选项卡上的“appSettings”部分中安全地存储这些值。此外,添加电话号码时,仅使用号码。
    请注意,还可以添加 SendGrid 凭据。 SendGrid 是电子邮件通知服务。 有关如何启用 SendGrid 的详细信息,请参阅标题为创建具有用户注册、电子邮件确认和密码重置功能的安全 ASP.NET Web 窗体应用的教程的“连接 SendGrid”部分。

    </connectionStrings>
      <appSettings>
        <!-- SendGrid Credentials-->    
        <add key="emailServiceUserName" value="[EmailServiceAccountUserName]" />
        <add key="emailServicePassword" value="[EmailServiceAccountPassword]" />
        <!-- Twilio Credentials-->
        <add key="SMSSID" value="[SMSServiceAccountSID]" />
        <add key="SMSAuthToken" value="[SMSServiceAuthorizationToken]" />
        <add key="SMSPhoneNumber" value="+[SMSPhoneNumber]" />    
      </appSettings>
      <system.web>
    

    警告

    安全性 - 从不将敏感数据存储在源代码中。 在此示例中,帐户和凭据存储在 Web.config 文件的 appSettings 部分中。 在 Azure 上,可以在 Azure 门户中 “配置”选项卡上安全地存储这些值。 有关相关信息,请参阅 Rick Anderson 的主题,主题标题为 最佳做法,介绍如何将密码和其他敏感数据部署到 ASP.NET 和 Azure

  5. 请在 App_Start\IdentityConfig.cs 文件中配置 SmsService 类,以应用以下用黄色标出的更改:

    public class SmsService : IIdentityMessageService
    {
        public Task SendAsync(IdentityMessage message)
        {
            var Twilio = new TwilioRestClient(
               ConfigurationManager.AppSettings["SMSSID"],
               ConfigurationManager.AppSettings["SMSAuthToken"]
            );
            var result = Twilio.SendMessage(
                ConfigurationManager.AppSettings["SMSPhoneNumber"],
               message.Destination, message.Body);
    
            // Status is one of Queued, Sending, Sent, Failed or null if the number is not valid
            Trace.TraceInformation(result.Status);
    
            // Twilio doesn't currently have an async API, so return success.
            return Task.FromResult(0);
        }
    }
    
  6. 将以下 using 语句添加到 IdentityConfig.cs 文件的开头:

    using Twilio;
    using System.Net;
    using System.Configuration;
    using System.Diagnostics;
    
  7. 通过删除黄色突出显示的行来更新 Account/Manage.aspx 文件:

    <%@ Page Title="Manage Account" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Manage.aspx.cs" Inherits="WebFormsTwoFactor.Account.Manage" %>
    
    <%@ Register Src="~/Account/OpenAuthProviders.ascx" TagPrefix="uc" TagName="OpenAuthProviders" %>
    
    <asp:Content ContentPlaceHolderID="MainContent" runat="server">
        <h2><%: Title %>.</h2>
    
        <div>
            <asp:PlaceHolder runat="server" ID="successMessage" Visible="false" ViewStateMode="Disabled">
                <p class="text-success"><%: SuccessMessage %></p>
            </asp:PlaceHolder>
        </div>
    
        <div class="row">
            <div class="col-md-12">
                <div class="form-horizontal">
                    <h4>Change your account settings</h4>
                    <hr />
                    <dl class="dl-horizontal">
                        <dt>Password:</dt>
                        <dd>
                            <asp:HyperLink NavigateUrl="/Account/ManagePassword" Text="[Change]" Visible="false" ID="ChangePassword" runat="server" />
                            <asp:HyperLink NavigateUrl="/Account/ManagePassword" Text="[Create]" Visible="false" ID="CreatePassword" runat="server" />
                        </dd>
                        <dt>External Logins:</dt>
                        <dd><%: LoginsCount %>
                            <asp:HyperLink NavigateUrl="/Account/ManageLogins" Text="[Manage]" runat="server" />
    
                        </dd>
                        <%--
                            Phone Numbers can used as a second factor of verification in a two-factor authentication system.
                            See <a href="https://go.microsoft.com/fwlink/?LinkId=313242">this article</a>
                            for details on setting up this ASP.NET application to support two-factor authentication using SMS.
                            Uncomment the following block after you have set up two-factor authentication
                        --%>
    
                        <dt>Phone Number:</dt>
                        <%--
                        <% if (HasPhoneNumber)
                           { %>
                        <dd>
                            <asp:HyperLink NavigateUrl="/Account/AddPhoneNumber" runat="server" Text="[Add]" />
                        </dd>
                        <% }
                           else
                           { %>
                        <dd>
                            <asp:Label Text="" ID="PhoneNumber" runat="server" />
                            <asp:HyperLink NavigateUrl="/Account/AddPhoneNumber" runat="server" Text="[Change]" /> &nbsp;|&nbsp;
                            <asp:LinkButton Text="[Remove]" OnClick="RemovePhone_Click" runat="server" />
                        </dd>
                        <% } %>
                        --%>
    
                        <dt>Two-Factor Authentication:</dt>
                        <dd>
                            <p>
                                There are no two-factor authentication providers configured. See <a href="https://go.microsoft.com/fwlink/?LinkId=313242">this article</a>
                                for details on setting up this ASP.NET application to support two-factor authentication.
                            </p>
                            <% if (TwoFactorEnabled)
                              { %> 
                            <%--
                            Enabled
                            <asp:LinkButton Text="[Disable]" runat="server" CommandArgument="false" OnClick="TwoFactorDisable_Click" />
                            --%>
                            <% }
                              else
                              { %> 
                            <%--
                            Disabled
                            <asp:LinkButton Text="[Enable]" CommandArgument="true" OnClick="TwoFactorEnable_Click" runat="server" />
                            --%>
                            <% } %>
                        </dd>
                    </dl>
                </div>
            </div>
        </div>
    </asp:Content>
    
  8. Manage.aspx.cs 的代码隐藏的 Page_Load 处理程序中,取消黄色突出显示的代码行的注释,使其如下所示:

    protected void Page_Load()
    {
        var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
    
        HasPhoneNumber = String.IsNullOrEmpty(manager.GetPhoneNumber(User.Identity.GetUserId()));
    
        // Enable this after setting up two-factor authentientication
        PhoneNumber.Text = manager.GetPhoneNumber(User.Identity.GetUserId()) ?? String.Empty;
    
        TwoFactorEnabled = manager.GetTwoFactorEnabled(User.Identity.GetUserId());
    
        LoginsCount = manager.GetLogins(User.Identity.GetUserId()).Count;
    
        var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
    
        if (!IsPostBack)
        {
            // Determine the sections to render
            if (HasPassword(manager))
            {
                ChangePassword.Visible = true;
            }
            else
            {
                CreatePassword.Visible = true;
                ChangePassword.Visible = false;
            }
    
            // Render success message
            var message = Request.QueryString["m"];
            if (message != null)
            {
                // Strip the query string from action
                Form.Action = ResolveUrl("~/Account/Manage");
    
                SuccessMessage =
                    message == "ChangePwdSuccess" ? "Your password has been changed."
                    : message == "SetPwdSuccess" ? "Your password has been set."
                    : message == "RemoveLoginSuccess" ? "The account was removed."
                    : message == "AddPhoneNumberSuccess" ? "Phone number has been added"
                    : message == "RemovePhoneNumberSuccess" ? "Phone number was removed"
                    : String.Empty;
                successMessage.Visible = !String.IsNullOrEmpty(SuccessMessage);
            }
        }
    }
    
  9. Account/TwoFactorAuthenticationSignIn.aspx.cs 的代码隐藏中,通过添加以下黄色突出显示的代码来更新 Page_Load 处理程序:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            var userId = signinManager.GetVerifiedUserId<ApplicationUser, string>();
            if (userId == null)
            {
                Response.Redirect("/Account/Error", true);
            }
            var userFactors = manager.GetValidTwoFactorProviders(userId);
            Providers.DataSource = userFactors.Select(x => x).ToList();
            Providers.DataBind();
        }
    }
    

    通过更改上述代码,包含身份验证选项的“提供程序”DropDownList 将不会重置为第一个值。 这将允许用户成功选择身份验证时使用的所有选项,而不仅仅是第一个选项。

  10. 解决方案资源管理器中,右键单击 Default.aspx 并选择 设置为起始页

  11. 通过测试应用,首先生成应用(Ctrl+Shift+B),然后运行应用(F5),然后选择 注册 以创建新用户帐户,或者选择 登录(如果用户帐户已注册)。

  12. (作为用户)登录后,单击导航栏中的用户 ID(电子邮件地址)以显示管理帐户页面 (Manage.aspx)。
    ASP.NET响应浏览器窗口的屏幕截图,其中用户ID被红色矩形突出显示。

  13. 管理帐户页上,单击电话号码旁边的添加
    “管理帐户”浏览器窗口的屏幕截图,其中显示了用于更改帐户设置的列表和选项链接。

  14. 添加你(作为用户)希望接收短信(文本消息)的电话号码,然后单击提交按钮。
    “电话号码”浏览器窗口的截图,显示“电话号码”字段中的输入值和“提交”按钮。
    此时,应用将使用来自 Web.config 的凭据来联系 Twilio。 短信(短信)将发送到与用户帐户关联的电话。 可以通过查看 Twilio 仪表板来验证 Twilio 消息是否已发送。

  15. 几秒钟后,与用户帐户关联的手机将收到包含验证码的短信。 输入验证码,然后按提交
    “验证电话号码”浏览器窗口的屏幕截图,其中显示了“代码”字段,其中包含输入的验证码和“提交”按钮。

为已注册用户启用 Two-Factor 身份验证

此时,你已为应用启用双重身份验证。 用户可以使用双因素身份验证,只需使用 UI 更改设置即可。

  1. 作为应用的用户,可以通过单击导航栏中的用户 ID(电子邮件别名)来为特定帐户启用双重身份验证,以显示 管理帐户 页面。然后,单击 “启用”链接,为帐户启用双重身份验证。“管理帐户”浏览器窗口的屏幕截图,其中显示了“启用”链接,其中突出显示了红色 Two-Factor 身份验证。
  2. 注销,然后重新登录。 如果已启用电子邮件,可以选择短信或电子邮件进行双重身份验证。 如果尚未启用电子邮件,请参阅标题为 创建具有用户注册的安全 ASP.NET Web 窗体应用、电子邮件确认和密码重置教程。Two-Factor 身份验证浏览器窗口的屏幕截图,其中显示了“选择 Two-Factor 身份验证提供程序”下拉列表。
  3. 将显示“Two-Factor 身份验证”页,你可以在其中输入代码(来自短信或电子邮件)。Two-Factor 身份验证浏览器窗口的屏幕截图,其中显示了“代码”字段,其中包含输入的验证码和“提交”按钮。
    单击 “记住此浏览器” 复选框,当使用选中该框的浏览器和设备时,即可免除使用双重身份验证进行登录。 只要恶意用户无法访问你的设备,启用双因素身份验证并单击记住此浏览器将为你提供方便的一步密码登录,同时仍保持对所有来自非信任设备访问的强大双因素身份验证保护。 可以在定期使用的任何专用设备上执行此操作。

其他资源