透過 ASP.NET Identity 使用簡訊和電子郵件進行的雙重要素驗證
作者 :、 Pranav Rastogi、 Rick Anderson、 Suhas Joshi
本教學課程將說明如何使用 SMS 和電子郵件設定雙因素驗證 (2FA) 。
本文是由 Rick Anderson (@RickAndMSFT @RickAndMSFT) 、Pranav Rastogi (@rustd) 、一文和 Suhas Joshi 所撰寫。 NuGet 範例主要是由 Factor Kung 所撰寫。
本主題包含下列項目:
建置身分識別範例
在本節中,您將使用 NuGet 來下載我們將使用的範例。 從安裝並執行Visual Studio Express 2013 for Web或Visual Studio 2013開始。 安裝 Visual Studio 2013 Update 2 或更高版本。
注意
警告:您必須安裝 Visual Studio 2013 Update 2 ,才能完成本教學課程。
建立新的 空白 ASP.NET Web 專案。
在 [套件管理員主控台] 中,輸入下列命令:
Install-Package SendGrid
Install-Package -Prerelease Microsoft.AspNet.Identity.Samples
在本教學課程中,我們將使用 SendGrid 來傳送電子郵件和 Twilio 或 ASPSMS 進行簡訊簡訊。 套件
Identity.Samples
會安裝我們將使用的程式碼。將 專案設定為使用 SSL。
選用:請遵循我的Email確認教學課程中的指示來連結 SendGrid,然後執行應用程式並註冊電子郵件帳戶。
選: 從範例中移除示範電子郵件連結確認碼 (
ViewBag.Link
帳戶控制器中的程式碼。DisplayEmail
請參閱 和ForgotPasswordConfirmation
動作方法和 razor 檢視) 。選: 從 Manage 和 Account 控制器中移除程式
ViewBag.Status
代碼,以及從 Views\Account\VerifyCode.cshtml 和 Views\Manage\VerifyPhoneNumber.cshtml razor 檢視中移除程式碼。 或者,您可以保留ViewBag.Status
顯示以測試此應用程式在本機的運作方式,而不需要連結及傳送電子郵件和簡訊。
注意
警告:如果您變更此範例中的任何安全性設定,生產應用程式將需要進行安全性稽核,以明確呼叫所做的變更。
設定雙因素驗證的 SMS
本教學課程提供使用 Twilio 或 ASPSMS 的指示,但您可以使用任何其他 SMS 提供者。
使用 SMS 提供者建立使用者帳戶
安裝其他套件或新增服務參考
Twilio:
在 [套件管理器主控台] 中,輸入下列命令:
Install-Package Twilio
ASPSMS:
必須新增下列服務參考:位址:
https://webservice.aspsms.com/aspsmsx2.asmx?WSDL
命名空間:
ASPSMSX2
找出 SMS 提供者使用者認證
Twilio:
從 Twilio 帳戶的 [ 儀表板 ] 索引標籤中,複製 [帳戶 SID ] 和 [ 驗證] 權杖。ASPSMS:
從您的帳戶設定中,流覽至 Userkey ,並將它與您的自我定義 密碼一起複製。我們稍後會將這些值儲存在 變數
SMSAccountIdentification
和SMSAccountPassword
中。指定 SenderID / Originator
Twilio:
從 [ 號碼] 索引 標籤中,複製您的 Twilio 電話號碼。ASPSMS:
在 [ 解除鎖定原始程式 ] 功能表中,解除鎖定一或多個 [原始程式],或選擇英數位元來源器 (所有網路) 不支援。我們稍後會將此值儲存在 變數
SMSAccountFrom
中。將 SMS 提供者認證傳輸至應用程式
讓認證和寄件者電話號碼可供應用程式使用:
public static class Keys { public static string SMSAccountIdentification = "My Idenfitication"; public static string SMSAccountPassword = "My Password"; public static string SMSAccountFrom = "+15555551234"; }
警告
安全性 - 永不將敏感性資料儲存在您的原始程式碼中。 帳戶和認證會新增至上述程式碼,以便讓範例保持簡單。 請參閱 Jon Atten ASP.NET MVC:將私人設定保留在原始檔控制外。
將資料傳輸至 SMS 提供者的實作
SmsService
在App_Start\IdentityConfig.cs檔案中設定 類別。視使用的 SMS 提供者而定,會啟用 Twilio 或 ASPSMS 區段:
public class SmsService : IIdentityMessageService { public Task SendAsync(IdentityMessage message) { // Twilio Begin // var Twilio = new TwilioRestClient( // Keys.SMSAccountIdentification, // Keys.SMSAccountPassword); // var result = Twilio.SendMessage( // Keys.SMSAccountFrom, // 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); // Twilio End // ASPSMS Begin // var soapSms = new WebApplication1.ASPSMSX2.ASPSMSX2SoapClient("ASPSMSX2Soap"); // soapSms.SendSimpleTextSMS( // Keys.SMSAccountIdentification, // Keys.SMSAccountPassword, // message.Destination, // Keys.SMSAccountFrom, // message.Body); // soapSms.Close(); // return Task.FromResult(0); // ASPSMS End } }
執行應用程式,並使用您先前註冊的帳戶登入。
按一下您的 [使用者識別碼],這會啟動
Index
控制器中的Manage
動作方法。按一下 [新增]。
幾秒鐘後,您會收到含有驗證碼的簡訊。 輸入它,然後按 [提交]。
[管理] 檢視會顯示已新增您的電話號碼。
檢查程式碼
// GET: /Account/Index
public async Task<ActionResult> Index(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two factor provider has been set."
: message == ManageMessageId.Error ? "An error has occurred."
: message == ManageMessageId.AddPhoneSuccess ? "The phone number was added."
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
: "";
var model = new IndexViewModel
{
HasPassword = HasPassword(),
PhoneNumber = await UserManager.GetPhoneNumberAsync(User.Identity.GetUserId()),
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(User.Identity.GetUserId()),
Logins = await UserManager.GetLoginsAsync(User.Identity.GetUserId()),
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(User.Identity.GetUserId())
};
return View(model);
}
控制器中的 Manage
動作方法會 Index
根據您先前的動作來設定狀態訊息,並提供變更本機密碼或新增本機帳戶的連結。 此方法 Index
也會顯示狀態或您的 2FA 電話號碼、外部登入、已啟用 2FA,並記住此瀏覽器的 2FA 方法, (稍後說明) 。 按一下標題列中 (電子郵件) 的使用者識別碼不會傳遞訊息。 按一下 [電話號碼:移除 ] 連結會以查詢字串的形式傳遞 Message=RemovePhoneSuccess
。
https://localhost:44300/Manage?Message=RemovePhoneSuccess
[]
AddPhoneNumber
動作方法會顯示對話方塊,以輸入可接收 SMS 訊息的電話號碼。
// GET: /Account/AddPhoneNumber
public ActionResult AddPhoneNumber()
{
return View();
}
按一下 [ 傳送驗證碼 ] 按鈕,將電話號碼張貼至 HTTP POST AddPhoneNumber
動作方法。
// POST: /Account/AddPhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Generate the token
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(
User.Identity.GetUserId(), model.Number);
if (UserManager.SmsService != null)
{
var message = new IdentityMessage
{
Destination = model.Number,
Body = "Your security code is: " + code
};
// Send token
await UserManager.SmsService.SendAsync(message);
}
return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
}
方法 GenerateChangePhoneNumberTokenAsync
會產生將在 SMS 訊息中設定的安全性權杖。 如果已設定 SMS 服務,權杖會以字串「您的安全性代碼為 < 權杖 > 」傳送。 方法 SmsService.SendAsync
會以非同步方式呼叫,然後將應用程式重新導向至 VerifyPhoneNumber
動作方法 (,其中會顯示下列對話方塊) ,您可以在其中輸入驗證碼。
輸入程式碼並按一下 [提交] 之後,程式碼就會張貼至 HTTP POST VerifyPhoneNumber
動作方法。
// POST: /Account/VerifyPhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code);
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess });
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "Failed to verify phone");
return View(model);
}
方法 ChangePhoneNumberAsync
會檢查張貼的安全性代碼。 如果程式碼正確,電話號碼會新增至 PhoneNumber
資料表的 AspNetUsers
欄位。 如果該呼叫成功,則會 SignInAsync
呼叫 方法:
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
// Clear the temporary cookies used for external and two factor sign ins
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie,
DefaultAuthenticationTypes.TwoFactorCookie);
AuthenticationManager.SignIn(new AuthenticationProperties
{
IsPersistent = isPersistent
},
await user.GenerateUserIdentityAsync(UserManager));
}
參數 isPersistent
會設定驗證會話是否會跨多個要求保存。
當您變更安全性設定檔時,會產生新的安全性戳記,並儲存在 SecurityStamp
AspNetUsers 資料表的 欄位中。 請注意, SecurityStamp
欄位與安全性 Cookie 不同。 安全性 Cookie 不會儲存在 AspNetUsers
資料表中 (或 Identity DB) 的任何其他位置。 安全性 Cookie 權杖是使用 DPAPI 自我簽署,並使用 和 到期時間資訊建立 UserId, SecurityStamp
。
Cookie 中介軟體會檢查每個要求的 Cookie。 類別 SecurityStampValidator
中的 Startup
方法會叫用 DB,並定期檢查安全性戳記,如 所 validateInterval
指定。 除非您變更安全性設定檔,否則只會在我們的範例) 中每隔 30 分鐘 (一次。 已選擇 30 分鐘的間隔,以將資料庫的車程降到最低。
SignInAsync
對安全性設定檔進行任何變更時,必須呼叫 方法。 當安全性設定檔變更時,資料庫會更新 SecurityStamp
欄位,而不需要呼叫 SignInAsync
方法,您 只會 在下次 OWIN 管線叫用資料庫時 validateInterval
() 為止。 您可以將 方法變更 SignInAsync
為立即傳回,並將 Cookie validateInterval
屬性從 30 分鐘設定為 5 秒,藉此進行測試:
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
return;
// Clear any partial cookies from external or two factor partial sign ins
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie,
DefaultAuthenticationTypes.TwoFactorCookie);
AuthenticationManager.SignIn(new AuthenticationProperties
{
IsPersistent = isPersistent
},
await user.GenerateUserIdentityAsync(UserManager));
}
public void ConfigureAuth(IAppBuilder app) {
// Configure the db context, user manager and role manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a
// third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider {
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add
// an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
//validateInterval: TimeSpan.FromMinutes(30),
validateInterval: TimeSpan.FromSeconds(5),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
透過上述程式碼變更,您可以變更安全性設定檔 (例如,藉由變更 已啟用 Two Factor enabled) 的狀態,並在方法失敗時 SecurityStampValidator.OnValidateIdentity
于 5 秒內登出。 移除 方法中的 SignInAsync
傳回行,進行另一個安全性設定檔變更,而且您將不會登出。方法 SignInAsync
會產生新的安全性 Cookie。
啟用雙因素驗證
在範例應用程式中,您必須使用 UI 來啟用雙因素驗證 (2FA) 。 若要啟用 2FA,請按一下導覽列中 (電子郵件別名) 的使用者識別碼。
按一下 [啟用 2FA]。
登出,然後重新登入。 如果您已啟用電子郵件 (請參閱 上一 個教學課程) ,您可以選取 2FA 的 SMS 或電子郵件。
[驗證代碼] 頁面隨即顯示,您可以從 SMS 或電子郵件) 輸入代碼 (。
按一下 [ 記住此瀏覽器 ] 核取方塊,即可免除您使用 2FA 登入該電腦和瀏覽器的需求。 啟用 2FA 並按一下 [記住此瀏覽器 ] 會提供您強式 2FA 保護,防止嘗試存取您的帳戶的惡意使用者,只要他們無法存取您的電腦即可。 您可以在您定期使用的任何私人電腦上執行此動作。 藉由設定 [記住此瀏覽器],您會從未定期使用的電腦取得 2FA 的新增安全性,而且您不需要在自己的電腦上通過 2FA 時獲得便利性。
如何註冊雙因素驗證提供者
當您建立新的 MVC 專案時, IdentityConfig.cs 檔案包含下列程式碼來註冊雙因素驗證提供者:
public static ApplicationUserManager Create(
IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var manager = new ApplicationUserManager(
new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// Register two factor authentication providers. This application uses Phone and Emails as a
// step of receiving a code for verifying the user
// You can write your own provider and plug it in here.
manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Your security code is: {0}"
});
manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is: {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>
(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
新增 2FA 的電話號碼
控制器 AddPhoneNumber
中的 Manage
動作方法會產生安全性權杖,並將它傳送至您提供的電話號碼。
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Generate the token and send it
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(
User.Identity.GetUserId(), model.Number);
if (UserManager.SmsService != null)
{
var message = new IdentityMessage
{
Destination = model.Number,
Body = "Your security code is: " + code
};
await UserManager.SmsService.SendAsync(message);
}
return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
}
傳送權杖之後,它會重新導向至 VerifyPhoneNumber
動作方法,您可以在其中輸入程式碼來註冊 2FA 的 SMS。 在您驗證電話號碼之前,不會使用 SMS 2FA。
啟用 2FA
EnableTFA
動作方法會啟用 2FA:
// POST: /Manage/EnableTFA
[HttpPost]
public async Task<ActionResult> EnableTFA()
{
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");
}
請注意,必須呼叫 , SignInAsync
因為 enable 2FA 是安全性設定檔的變更。 啟用 2FA 時,使用者必須使用 2FA 登入,並使用他們在範例) 中註冊的 2FA 方法 (SMS 和電子郵件。
您可以新增更多 2FA 提供者,例如 QR 代碼產生器,也可以自行撰寫。
注意
2FA 代碼是使用 以時間為基礎的單次密碼演算法 所產生,而且代碼有效期為六分鐘。 如果您輸入程式碼需要六分鐘以上的時間,您會收到不正確程式碼錯誤訊息。
結合社交和本機登入帳戶
您可以按一下電子郵件連結來合併本機和社交帳戶。 在下列順序中,「 RickAndMSFT@gmail.com 」 會先建立為本機登入,但您可以先將帳戶建立為社交記錄,然後新增本機登入。
按一下 [ 管理] 連結。 請注意與此帳戶相關聯的 0 個外部 (社交登入) 。
按一下另一個登入服務的連結,並接受應用程式要求。 這兩個帳戶已合併,您將能夠使用任一帳戶登入。 您可能會想要讓使用者新增本機帳戶,以防其社交記錄驗證服務已關閉,或者他們可能失去其社交帳戶的存取權。
在下圖中,Tom 是 (中的社交記錄 ,您可以從外部登入看到:1 顯示在頁面上) 。
按一下 [挑選密碼 ] 可讓您新增與相同帳戶相關聯的本機登入。
帳戶從暴力密碼破解攻擊鎖定
您可以藉由啟用使用者鎖定來保護應用程式上的帳戶免于字典攻擊。 方法中的 ApplicationUserManager Create
下列程式碼會設定鎖定:
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
上述程式碼只允許鎖定雙因素驗證。 雖然您可以在帳戶控制器的 方法中 Login
變更 shouldLockout
為 true 來啟用登入鎖定,但建議您不要針對登入啟用鎖定,因為它會使帳戶容易受到DOS登入攻擊。 在範例程式碼中,會針對在 ApplicationDbInitializer Seed
方法中建立的系統管理員帳戶停用鎖定:
public static void InitializeIdentityForEF(ApplicationDbContext db)
{
var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
const string name = "admin@example.com";
const string roleName = "Admin";
//Create Role Admin if it does not exist
var role = roleManager.FindByName(roleName);
if (role == null)
{
role = new IdentityRole(roleName);
var roleresult = roleManager.Create(role);
}
var user = userManager.FindByName(name);
if (user == null)
{
user = new ApplicationUser { UserName = name, Email = name };
var result = userManager.Create(user, GetSecurePassword());
result = userManager.SetLockoutEnabled(user.Id, false);
}
// Add user admin to Role Admin if not already added
var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name))
{
var result = userManager.AddToRole(user.Id, role.Name);
}
}
要求使用者擁有已驗證的電子郵件帳戶
下列程式碼需要使用者擁有已驗證的電子郵件帳戶,才能登入:
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Require the user to have a confirmed email before they can log on.
var user = await UserManager.FindByNameAsync(model.Email);
if (user != null)
{
if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
ViewBag.errorMessage = "You must have a confirmed email to log on.";
return View("Error");
}
}
// This doen't count login failures towards lockout only two factor authentication
// To enable password failures to trigger lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password,
model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
SignInManager 如何檢查 2FA 需求
本機登入和社交記錄都會檢查是否已啟用 2FA。 如果已啟用 2FA, SignInManager
則登入方法會 SignInStatus.RequiresVerification
傳回 ,而使用者將會重新導向至 SendCode
動作方法,其中必須輸入程式碼才能依序完成登入。 如果使用者已在使用者本機 Cookie 上設定 RememberMe,則會 SignInManager
傳回 SignInStatus.Success
,而且他們不需要通過 2FA。
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Require the user to have a confirmed email before they can log on.
var user = await UserManager.FindByNameAsync(model.Email);
if (user != null)
{
if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
ViewBag.errorMessage = "You must have a confirmed email to log on.";
return View("Error");
}
}
// This doen't count login failures towards lockout only two factor authentication
// To enable password failures to trigger lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password,
model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
// Sign in the user with this external login provider if the user already has a login
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
case SignInStatus.Failure:
default:
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
}
}
下列程式碼顯示 SendCode
動作方法。
SelectListItem會建立,並啟用使用者的所有 2FA 方法。
SelectListItem會傳遞至DropDownListFor協助程式,讓使用者選取 2FA 方法 (通常是電子郵件和簡訊) 。
public async Task<ActionResult> SendCode(string returnUrl)
{
var userId = await SignInManager.GetVerifiedUserIdAsync();
if (userId == null)
{
return View("Error");
}
var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(userId);
var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl });
}
一旦使用者張貼 2FA 方法之後, HTTP POST SendCode
會呼叫動作方法、 SignInManager
傳送 2FA 程式碼,並將使用者重新導向至 VerifyCode
動作方法,讓他們可以在其中輸入程式碼以完成登入。
//
// POST: /Account/SendCode
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SendCode(SendCodeViewModel model)
{
if (!ModelState.IsValid)
{
return View();
}
// Generate the token and send it
if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider))
{
return View("Error");
}
return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl });
}
2FA 鎖定
雖然您可以在登入密碼嘗試失敗時設定帳戶鎖定,但這種方法會使您的登入容易遭受 DOS 鎖定。 建議您只搭配 2FA 使用帳戶鎖定。
ApplicationUserManager
建立 時,範例程式碼會將 2FA 鎖定和 MaxFailedAccessAttemptsBeforeLockout
設定為五。 一旦使用者透過本機帳戶或社交帳戶) 登入 (,就會儲存 2FA 的每個失敗嘗試,如果達到最大嘗試,使用者就會鎖定五分鐘, (您可以使用) 來設定鎖定時間 DefaultAccountLockoutTimeSpan
。
其他資源
- ASP.NET 身分識別建議的資源 身分識別部落格、影片、教學課程和絕佳 SO 連結的完整清單。
- MVC 5 應用程式與 Facebook、Twitter、LinkedIn和 Google OAuth2 登入 也會示範如何將設定檔資訊新增至使用者資料表。
- ASP.NET MVC 和身分識別 2.0:瞭解 John Atten 的基本概念 。
- 具有 ASP.NET 身分識別的帳戶確認和密碼復原
- ASP.NET Identity 簡介
- 宣告 Pranav Rastogi ASP.NET Identity 2.0.0 的 RTM。
- ASP.NET 身分識別 2.0:設定 John Atten 的帳戶驗證和Two-Factor授權 。