Aplicación de ASP.NET MVC 5 con autenticación en dos fases por SMS y correo electrónico

Por Rick Anderson

En este tutorial se muestra cómo compilar una aplicación web ASP.NET MVC 5 con autenticación en dos fases. Debe completar el tutorial Creación de una aplicación web ASP.NET MVC 5 segura con inicio de sesión, confirmación por correo electrónico y restablecimiento de contraseña antes de continuar. Puede descargar la aplicación completada aquí. La descarga contiene asistentes de depuración que le permiten probar la confirmación por correo electrónico y SMS sin configurar un proveedor de correo electrónico o de SMS.

Este tutorial lo ha escrito Rick Anderson (Twitter: @RickAndMSFT).

Creación de una aplicación ASP.NET MVC

Empiece por instalar y ejecutar Visual Studio Express 2013 para Web o una versión posterior.

Nota:

Advertencia: Debe completar el tutorial Creación de una aplicación web ASP.NET MVC 5 segura con inicio de sesión, confirmación por correo electrónico y restablecimiento de contraseña antes de continuar. Debe instalar Visual Studio 2013 Update 3 o una versión posterior para completar este tutorial.

  1. Cree un nuevo proyecto web de ASP.NET y seleccione la plantilla MVC. Web Forms también admite ASP.NET Identity, por lo que puede seguir pasos similares en una aplicación de formularios web.
    Screenshot that shows the New A S P dot NET Project window. The default authentication, Individual User Accounts, is highlighted.
  2. Deje la autenticación predeterminada como Cuentas de usuario individuales. Si quiere hospedar la aplicación en Azure, deje activada la casilla. Más adelante en el tutorial la implementará en Azure. Puede abrir una cuenta de Azure de forma gratuita.
  3. Establezca el proyecto para usar SSL.

Configuración de SMS para la autenticación en dos fases

En este tutorial se proporcionan instrucciones para usar Twilio o ASPSMS, pero puede usar cualquier otro proveedor de SMS.

  1. Creación de una cuenta de usuario con un proveedor de SMS

    Cree una cuenta de Twilio o ASPSMS.

  2. Instalación de paquetes adicionales o adición de referencias de servicio

    Twilio:
    En la Consola del Administrador de paquetes, escriba el siguiente comando:
    Install-Package Twilio

    ASPSMS:
    Es necesario agregar la siguiente referencia de servicio:

    Screenshot that shows the Add Service Reference window. The Address and Namespace input bars are highlighted.

    Dirección:
    https://webservice.aspsms.com/aspsmsx2.asmx?WSDL

    Espacio de nombres:
    ASPSMSX2

  3. Averiguar las credenciales de usuario del proveedor de SMS

    Twilio:
    En la pestaña Panel de la cuenta de Twilio, copie el SID de cuenta y el token de autenticación.

    ASPSMS:
    En la configuración de la cuenta, vaya a Clave de usuario y cópiela junto con la contraseña autodefinida.

    Más adelante almacenaremos estos valores en el archivo web.config dentro de las claves "SMSAccountIdentification" y "SMSAccountPassword".

  4. Especificación de id. del emisor/originador

    Twilio:
    En la pestaña Números, copie su número de teléfono de Twilio.

    ASPSMS:
    En el menú Desbloquear originadores, desbloquee uno o varios originadores o elija un originador alfanumérico (no es compatible con todas las redes).

    Más adelante almacenaremos este valor en el archivo web.config dentro de la clave "SMSAccountFrom".

  5. Transferencia de credenciales del proveedor de SMS a la aplicación

    Haga que las credenciales y el número de teléfono del remitente estén disponibles para la aplicación. Para simplificar, almacenaremos estos valores en el archivo web.config. Al implementar en Azure, podemos almacenar los valores de forma segura en la sección de Configuración de aplicaciones en la pestaña Configurar del sitio web.

    </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>
    

    Advertencia

    Seguridad: nunca almacene datos confidenciales en el código fuente. La cuenta y las credenciales se agregan al código anterior para simplificar el ejemplo. Vea Prácticas recomendadas para implementar contraseñas y otros datos confidenciales en ASP.NET y Azure.

  6. Implementación de la transferencia de datos al proveedor de SMS

    Configure la clase SmsService en el archivo App_Start\IdentityConfig.cs.

    En función del proveedor de SMS usado, active la sección Twilio o 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
        }
    }
    
  7. Actualice la vista de Razor Views\Manage\Index.cshtml: (nota: no solo quite los comentarios en el código de salida, use el código siguiente).

    @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. Compruebe que los métodos de acción EnableTwoFactorAuthentication y DisableTwoFactorAuthentication en ManageController tengan el atributo [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");
    }
    
  9. Ejecute la aplicación e inicie sesión con la cuenta que registró anteriormente.

  10. Haga clic en el identificador de usuario, que activa el método de acción Index en el controlador Manage.
    Screenshot that shows the A S P dot NET app Home page. A Sample USER I D is highlighted.

  11. Haga clic en Agregar.
    Screenshot that shows the A S P dot NET app Account Settings page. None Add next to Phone Number section is highlighted.

  12. El método de acción AddPhoneNumber muestra un cuadro de diálogo para escribir un número de teléfono que puede recibir mensajes SMS.

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

    Screenshot that shows the A S P dot NET app Add Phone Number page. A sample phone number is filled in with a Send Verification Code button below it.

  13. En unos segundos recibirá un mensaje de texto con el código de verificación. Introdúzcalo y presione Enviar.
    Screenshot of the A S P dot NET app Add Phone Number page showing an input bar filled with a sample verification code and a Submit button below it.

  14. La vista Administrar muestra que se ha agregado el número de teléfono.

Habilitación de la autenticación en dos fases

En la aplicación generada por la plantilla, debe usar la interfaz de usuario para habilitar la autenticación en dos fases (2FA). Para habilitar 2FA, haga clic en el identificador de usuario (alias de correo electrónico) en la barra de navegación.

Screenshot that displays the A S P dot NET app Home page. A sample USER I D is highlighted.

Haga clic en habilitar 2FA.

Screenshot that shows the A S P dot NET app Account Settings page. Two-Factor Authentication: Disabled with an Enable link section is highlighted.

Cierre sesión y vuelva a iniciar sesión. Si ha habilitado el correo electrónico (consulte el tutorial anterior), puede seleccionar el SMS o el correo electrónico para 2FA.

Screenshot that shows the A S P dot NET app Send Verification Code page. A dropdown menu showing Phone Code and Email Code is selected.

La página Comprobar código se muestra donde puede escribir el código (desde SMS o correo electrónico).

Screenshot that shows the A S P dot NET app Verify page for 2 FA. Beneath a sample code, a checkbox with Remember this browser is highlighted.

Al hacer clic en la casilla Recordar este explorador, se le eximirá de tener que usar 2FA para iniciar sesión al usar el dispositivo y el explorador donde ha activado la casilla. Siempre que los usuarios malintencionados no puedan obtener acceso al dispositivo, habilitar 2FA y hacer clic en el botón Recordar este explorador le proporcionará un cómodo acceso con contraseña mediante un solo paso mientras conserva la protección segura de 2FA para todo el acceso desde dispositivos que no son de confianza. Puede hacerlo en cualquier dispositivo privado que use con regularidad.

En este tutorial se proporciona una introducción rápida a la habilitación de 2FA en una nueva aplicación ASP.NET MVC. Mi tutorial Autenticación en dos fases mediante SMS y correo electrónico con ASP.NET Identity profundiza en el código subyacente del ejemplo.

Recursos adicionales