"
ASP.NET (snapshot 2017) Microsoft documentation and samples

Two-factor authentication with SMS

By Rick Anderson and Swiss-Devs

This tutorial applies to ASP.NET Core 1.x only. See (xref:)Enabling QR Code generation for authenticator apps in ASP.NET Core for ASP.NET Core 2.0 and later.

This tutorial shows how to set up two-factor authentication (2FA) using SMS. Instructions are given for twilio and ASPSMS, but you can use any other SMS provider. We recommend you complete Account Confirmation and Password Recovery before starting this tutorial.

View the completed sample. (xref:)How to download.

Create a new ASP.NET Core project

Create a new ASP.NET Core web app named Web2FA with individual user accounts. Follow the instructions in (xref:)Enforcing SSL in an ASP.NET Core app to set up and require SSL.

Create an SMS account

Create an SMS account, for example, from twilio or ASPSMS. Record the authentication credentials (for twilio: accountSid and authToken, for ASPSMS: Userkey and Password).

Figuring out SMS Provider credentials

Twilio:
From the Dashboard tab of your Twilio account, copy the Account SID and Auth token.

ASPSMS:
From your account settings, navigate to Userkey and copy it together with your Password.

We will later store these values in with the secret-manager tool within the keys SMSAccountIdentification and SMSAccountPassword.

Specifying SenderID / Originator

Twilio:
From the Numbers tab, copy your Twilio phone number.

ASPSMS:
Within the Unlock Originators Menu, unlock one or more Originators or choose an alphanumeric Originator (Not supported by all networks).

We will later store this value with the secret-manager tool within the key SMSAccountFrom.

Provide credentials for the SMS service

We’ll use the (xref:)Options pattern to access the user account and key settings.

[!code-csharpMain]

   1:  namespace Web2FA.Services
   2:  {
   3:      public class SMSoptions
   4:      {
   5:          public string SMSAccountIdentification { get; set; }
   6:          public string SMSAccountPassword { get; set; }
   7:          public string SMSAccountFrom { get; set; }
   8:      }
   9:  }

Set the SMSAccountIdentification, SMSAccountPassword and SMSAccountFrom with the (xref:)secret-manager tool. For example:

C:/Web2FA/src/WebApp1>dotnet user-secrets set SMSAccountIdentification 12345
info: Successfully saved SMSAccountIdentification = 12345 to the secret store.

Twilio:
Install-Package Twilio

ASPSMS:
Install-Package ASPSMS

Twilio:
[!code-csharpMain]

   1:  using Microsoft.Extensions.Options;
   2:  using System.Threading.Tasks;
   3:  using Twilio;
   4:  using Twilio.Rest.Api.V2010.Account;
   5:  using Twilio.Types;
   6:   
   7:  namespace Web2FA.Services
   8:  {
   9:      // This class is used by the application to send Email and SMS
  10:      // when you turn on two-factor authentication in ASP.NET Identity.
  11:      // For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
  12:      public class AuthMessageSender : IEmailSender, ISmsSender
  13:      {
  14:          public AuthMessageSender(IOptions<SMSoptions> optionsAccessor)
  15:          {
  16:              Options = optionsAccessor.Value;
  17:          }
  18:   
  19:          public SMSoptions Options { get; }  // set only via Secret Manager
  20:   
  21:          public Task SendEmailAsync(string email, string subject, string message)
  22:          {
  23:              // Plug in your email service here to send an email.
  24:              return Task.FromResult(0);
  25:          }
  26:   
  27:          public Task SendSmsAsync(string number, string message)
  28:          {
  29:              // Plug in your SMS service here to send a text message.
  30:              // Your Account SID from twilio.com/console
  31:              var accountSid = Options.SMSAccountIdentification;
  32:              // Your Auth Token from twilio.com/console
  33:              var authToken = Options.SMSAccountPassword;
  34:   
  35:              TwilioClient.Init(accountSid, authToken);
  36:   
  37:              return MessageResource.CreateAsync(
  38:                to: new PhoneNumber(number),
  39:                from: new PhoneNumber(Options.SMSAccountFrom),
  40:                body: message);
  41:          }
  42:      }
  43:  }

ASPSMS:
[!code-csharpMain]

   1:  using Microsoft.Extensions.Options;
   2:  using System.Threading.Tasks;
   3:   
   4:  namespace Web2FA.Services
   5:  {
   6:      // This class is used by the application to send Email and SMS
   7:      // when you turn on two-factor authentication in ASP.NET Identity.
   8:      // For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
   9:      public class AuthMessageSender : IEmailSender, ISmsSender
  10:      {
  11:          public AuthMessageSender(IOptions<SMSoptions> optionsAccessor)
  12:          {
  13:              Options = optionsAccessor.Value;
  14:          }
  15:   
  16:          public SMSoptions Options { get; }  // set only via Secret Manager
  17:   
  18:          public Task SendEmailAsync(string email, string subject, string message)
  19:          {
  20:              // Plug in your email service here to send an email.
  21:              return Task.FromResult(0);
  22:          }
  23:   
  24:          public Task SendSmsAsync(string number, string message)
  25:          {
  26:              ASPSMS.SMS SMSSender = new ASPSMS.SMS();
  27:   
  28:              SMSSender.Userkey = Options.SMSAccountIdentification;
  29:              SMSSender.Password = Options.SMSAccountPassword;
  30:              SMSSender.Originator = Options.SMSAccountFrom;
  31:   
  32:              SMSSender.AddRecipient(number);
  33:              SMSSender.MessageData = message;
  34:   
  35:              SMSSender.SendTextSMS();
  36:   
  37:              return Task.FromResult(0);
  38:          }
  39:      }
  40:  }

Configure startup to use SMSoptions

Add SMSoptions to the service container in the ConfigureServices method in the Startup.cs:

[!code-csharpMain]

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Threading.Tasks;
   5:  using Microsoft.AspNetCore.Builder;
   6:  using Microsoft.AspNetCore.Hosting;
   7:  using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
   8:  using Microsoft.EntityFrameworkCore;
   9:  using Microsoft.Extensions.Configuration;
  10:  using Microsoft.Extensions.DependencyInjection;
  11:  using Microsoft.Extensions.Logging;
  12:  using Web2FA.Data;
  13:  using Web2FA.Models;
  14:  using Web2FA.Services;
  15:   
  16:  namespace Web2FA
  17:  {
  18:      public class Startup
  19:      {
  20:          public Startup(IHostingEnvironment env)
  21:          {
  22:              var builder = new ConfigurationBuilder()
  23:                  .SetBasePath(env.ContentRootPath)
  24:                  .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
  25:                  .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
  26:   
  27:              if (env.IsDevelopment())
  28:              {
  29:                  // For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
  30:                  builder.AddUserSecrets<Startup>();
  31:              }
  32:   
  33:              builder.AddEnvironmentVariables();
  34:              Configuration = builder.Build();
  35:          }
  36:   
  37:          public IConfigurationRoot Configuration { get; }
  38:   
  39:          // This method gets called by the runtime. Use this method to add services to the container.
  40:          #region snippet2
  41:          public void ConfigureServices(IServiceCollection services)
  42:          {
  43:              // Add framework services.
  44:              services.AddDbContext<ApplicationDbContext>(options =>
  45:                  options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
  46:   
  47:              services.AddIdentity<ApplicationUser, IdentityRole>()
  48:                  .AddEntityFrameworkStores<ApplicationDbContext>()
  49:                  .AddDefaultTokenProviders();
  50:   
  51:              services.AddMvc();
  52:   
  53:              services.Configure<IdentityOptions>(options =>
  54:              {
  55:                  options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
  56:                  options.Lockout.MaxFailedAccessAttempts = 10;
  57:              });
  58:   
  59:              #region snippet1
  60:              // Add application services.
  61:              services.AddTransient<IEmailSender, AuthMessageSender>();
  62:              services.AddTransient<ISmsSender, AuthMessageSender>();
  63:              services.Configure<SMSoptions>(Configuration);
  64:          }
  65:          #endregion
  66:          #endregion
  67:   
  68:          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  69:          public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  70:          {
  71:              loggerFactory.AddConsole(Configuration.GetSection("Logging"));
  72:              loggerFactory.AddDebug();
  73:   
  74:              if (env.IsDevelopment())
  75:              {
  76:                  app.UseDeveloperExceptionPage();
  77:                  app.UseDatabaseErrorPage();
  78:                  app.UseBrowserLink();
  79:              }
  80:              else
  81:              {
  82:                  app.UseExceptionHandler("/Home/Error");
  83:              }
  84:   
  85:              app.UseStaticFiles();
  86:   
  87:              app.UseIdentity();
  88:   
  89:              // Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
  90:   
  91:              app.UseMvc(routes =>
  92:              {
  93:                  routes.MapRoute(
  94:                      name: "default",
  95:                      template: "{controller=Home}/{action=Index}/{id?}");
  96:              });
  97:          }
  98:      }
  99:  }

Enable two-factor authentication

Open the Views/Manage/Index.cshtml Razor view file and remove the comment characters (so no markup is commnted out).

Log in with two-factor authentication

Web application Register view open in Microsoft Edge
Web application Register view open in Microsoft Edge
Manage view
Manage view
Add Phone Number page
Add Phone Number page
Verify Phone Number page
Verify Phone Number page

If you don’t get a text message, see twilio log page.

Manage view
Manage view
Manage view
Manage view

Test two-factor authentication

Send Verification Code view
Send Verification Code view
Verify view
Verify view

Account lockout for protecting against brute force attacks

We recommend you use account lockout with 2FA. Once a user logs in (through a local account or social account), each failed attempt at 2FA is stored, and if the maximum attempts (default is 5) is reached, the user is locked out for five minutes (you can set the lock out time with DefaultAccountLockoutTimeSpan). The following configures Account to be locked out for 10 minutes after 10 failed attempts.

[!code-csharpMain]

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Threading.Tasks;
   5:  using Microsoft.AspNetCore.Builder;
   6:  using Microsoft.AspNetCore.Hosting;
   7:  using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
   8:  using Microsoft.EntityFrameworkCore;
   9:  using Microsoft.Extensions.Configuration;
  10:  using Microsoft.Extensions.DependencyInjection;
  11:  using Microsoft.Extensions.Logging;
  12:  using Web2FA.Data;
  13:  using Web2FA.Models;
  14:  using Web2FA.Services;
  15:   
  16:  namespace Web2FA
  17:  {
  18:      public class Startup
  19:      {
  20:          public Startup(IHostingEnvironment env)
  21:          {
  22:              var builder = new ConfigurationBuilder()
  23:                  .SetBasePath(env.ContentRootPath)
  24:                  .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
  25:                  .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
  26:   
  27:              if (env.IsDevelopment())
  28:              {
  29:                  // For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
  30:                  builder.AddUserSecrets<Startup>();
  31:              }
  32:   
  33:              builder.AddEnvironmentVariables();
  34:              Configuration = builder.Build();
  35:          }
  36:   
  37:          public IConfigurationRoot Configuration { get; }
  38:   
  39:          // This method gets called by the runtime. Use this method to add services to the container.
  40:          #region snippet2
  41:          public void ConfigureServices(IServiceCollection services)
  42:          {
  43:              // Add framework services.
  44:              services.AddDbContext<ApplicationDbContext>(options =>
  45:                  options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
  46:   
  47:              services.AddIdentity<ApplicationUser, IdentityRole>()
  48:                  .AddEntityFrameworkStores<ApplicationDbContext>()
  49:                  .AddDefaultTokenProviders();
  50:   
  51:              services.AddMvc();
  52:   
  53:              services.Configure<IdentityOptions>(options =>
  54:              {
  55:                  options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
  56:                  options.Lockout.MaxFailedAccessAttempts = 10;
  57:              });
  58:   
  59:              #region snippet1
  60:              // Add application services.
  61:              services.AddTransient<IEmailSender, AuthMessageSender>();
  62:              services.AddTransient<ISmsSender, AuthMessageSender>();
  63:              services.Configure<SMSoptions>(Configuration);
  64:          }
  65:          #endregion
  66:          #endregion
  67:   
  68:          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  69:          public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  70:          {
  71:              loggerFactory.AddConsole(Configuration.GetSection("Logging"));
  72:              loggerFactory.AddDebug();
  73:   
  74:              if (env.IsDevelopment())
  75:              {
  76:                  app.UseDeveloperExceptionPage();
  77:                  app.UseDatabaseErrorPage();
  78:                  app.UseBrowserLink();
  79:              }
  80:              else
  81:              {
  82:                  app.UseExceptionHandler("/Home/Error");
  83:              }
  84:   
  85:              app.UseStaticFiles();
  86:   
  87:              app.UseIdentity();
  88:   
  89:              // Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
  90:   
  91:              app.UseMvc(routes =>
  92:              {
  93:                  routes.MapRoute(
  94:                      name: "default",
  95:                      template: "{controller=Home}/{action=Index}/{id?}");
  96:              });
  97:          }
  98:      }
  99:  }



Comments ( )
Link to this page: //www.vb-net.com/AspNet-DocAndSamples-2017/aspnetcore/security/authentication/2fa.htm
< THANKS ME>