Zweistufige Authentifizierung mithilfe von SMS und E-Mails mit ASP.NET Identity
von Hao Kung, Pranav Rastogi, Rick Anderson, Suhas Joshi
In diesem Tutorial erfahren Sie, wie Sie die zweistufige Authentifizierung (2FA) mithilfe von SMS und E-Mail einrichten.
Dieser Artikel wurde von Rick Anderson (@RickAndMSFT), Pranav Rastogi (@rustd), Hao Kung und Suhas Joshi geschrieben. Das NuGet-Beispiel wurde hauptsächlich von Hao Kung geschrieben.
In diesem Thema werden folgende Themen behandelt:
- Erstellen des Identitätsbeispiels
- Einrichten von SMS für die zweistufige Authentifizierung
- Aktivieren der zweistufigen Authentifizierung
- Registrieren eines Anbieters für die zweistufige Authentifizierung
- Kombinieren von sozialen und lokalen Anmeldekonten
- Kontosperrung vor Brute-Force-Angriffen
Erstellen des Identitätsbeispiels
In diesem Abschnitt verwenden Sie NuGet, um ein Beispiel herunterzuladen, mit dem wir arbeiten werden. Beginnen Sie mit der Installation und Ausführung Visual Studio Express 2013 für Web oder Visual Studio 2013. Installieren Sie Visual Studio 2013 Update 2 oder höher.
Hinweis
Warnung: Sie müssen Visual Studio 2013 Update 2 installieren, um dieses Tutorial abzuschließen.
Erstellen Sie ein neues leeres ASP.NET Webprojekt.
Geben Sie in der Paket-Manager-Konsole die folgenden Befehle ein:
Install-Package SendGrid
Install-Package -Prerelease Microsoft.AspNet.Identity.Samples
In diesem Tutorial verwenden wir SendGrid zum Senden von E-Mails und Twilio oder ASPSMS für SMS. Das
Identity.Samples
Paket installiert den Code, mit dem wir arbeiten werden.Legen Sie das Projekt so fest, dass SSL verwendet wird.
Optional: Befolgen Sie die Anweisungen in meinem Email Bestätigungstutorial, um SendGrid zu integrieren, dann die App auszuführen und ein E-Mail-Konto zu registrieren.
Optional: Entfernen Sie den Bestätigungscode für den Demo-E-Mail-Link aus dem Beispiel (Der
ViewBag.Link
Code im Kontocontroller. Weitere Informationen finden Sie unter denDisplayEmail
Aktionsmethoden undForgotPasswordConfirmation
razor-Ansichten .Optional: Entfernen Sie den
ViewBag.Status
Code aus den Controllern Verwalten und Konto sowie aus den Razor-Ansichten Views\Account\VerifyCode.cshtml und Views\Manage\VerifyPhoneNumber.cshtml . Alternativ können Sie dieViewBag.Status
Anzeige beibehalten, um zu testen, wie diese App lokal funktioniert, ohne eine Verbindung herstellen und E-Mail- und SMS-Nachrichten senden zu müssen.
Hinweis
Warnung: Wenn Sie eine der Sicherheitseinstellungen in diesem Beispiel ändern, müssen Produktions-Apps einer Sicherheitsüberwachung unterzogen werden, die die vorgenommenen Änderungen explizit aufruft.
Einrichten von SMS für die zweistufige Authentifizierung
Dieses Tutorial enthält Anweisungen für die Verwendung von Twilio oder ASPSMS, aber Sie können jeden anderen SMS-Anbieter verwenden.
Erstellen eines Benutzerkontos mit einem SMS-Anbieter
Erstellen Sie ein Twilio - oder ASPSMS-Konto .
Installieren zusätzlicher Pakete oder Hinzufügen von Dienstverweisen
Twilio:
Geben Sie in der Paket-Manager-Konsole den folgenden Befehl ein:
Install-Package Twilio
ASPSMS:
Der folgende Dienstverweis muss hinzugefügt werden:Adresse:
https://webservice.aspsms.com/aspsmsx2.asmx?WSDL
Namespace:
ASPSMSX2
Ermitteln der Benutzeranmeldeinformationen des SMS-Anbieters
Twilio:
Kopieren Sie auf der Registerkarte Dashboard Ihres Twilio-Kontos die Konto-SID und das Authentifizierungstoken.ASPSMS:
Navigieren Sie in Ihren Kontoeinstellungen zu Userkey , und kopieren Sie ihn zusammen mit Ihrem selbst definierten Kennwort.Diese Werte werden später in den Variablen
SMSAccountIdentification
undSMSAccountPassword
gespeichert.Angeben von SenderID/Originator
Twilio:
Kopieren Sie auf der Registerkarte Nummern Ihre Twilio-Telefonnummer.ASPSMS:
Entsperren Sie im Menü Entsperren von Originators einen oder mehrere Originators, oder wählen Sie einen alphanumerischen Absender aus (nicht von allen Netzwerken unterstützt).Dieser Wert wird später in der Variablen
SMSAccountFrom
gespeichert.Übertragen von Anmeldeinformationen des SMS-Anbieters in die App
Stellen Sie die Anmeldeinformationen und die Telefonnummer des Absenders für die App zur Verfügung:
public static class Keys { public static string SMSAccountIdentification = "My Idenfitication"; public static string SMSAccountPassword = "My Password"; public static string SMSAccountFrom = "+15555551234"; }
Warnung
Sicherheit: Speichern Sie vertrauliche Daten niemals in Ihrem Quellcode. Das Konto und die Anmeldeinformationen werden dem obigen Code hinzugefügt, um das Beispiel einfach zu halten. Weitere Informationen finden Sie unter Jon Attens ASP.NET MVC: Private Einstellungen außerhalb der Quellcodeverwaltung beibehalten.
Implementierung der Datenübertragung an den SMS-Anbieter
Konfigurieren Sie die
SmsService
-Klasse in der Datei App_Start\IdentityConfig.cs .Je nach verwendeter SMS-Anbieter aktivieren Sie entweder den Abschnitt Twilio oder 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 } }
Führen Sie die App aus, und melden Sie sich mit dem Konto an, das Sie zuvor registriert haben.
Klicken Sie auf Ihre Benutzer-ID, wodurch die
Index
Aktionsmethode imManage
Controller aktiviert wird.Klicken Sie auf Hinzufügen.
In wenigen Sekunden erhalten Sie eine SMS mit dem Überprüfungscode. Geben Sie es ein, und drücken Sie Senden.
Die Ansicht Verwalten zeigt, dass Ihre Telefonnummer hinzugefügt wurde.
Untersuchen des Codes
// 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);
}
Die Index
Aktionsmethode im Manage
Controller legt die status Nachricht basierend auf Ihrer vorherigen Aktion fest und stellt Links bereit, um Ihr lokales Kennwort zu ändern oder ein lokales Konto hinzuzufügen. Die Index
-Methode zeigt auch den Zustand oder Ihre 2FA-Telefonnummer, externe Anmeldungen, aktivierte 2FA und die 2FA-Methode für diesen Browser an (weiter unten erläutert). Wenn Sie in der Titelleiste auf Ihre Benutzer-ID (E-Mail) klicken, wird keine Nachricht übergeben. Klicken Sie auf telefonnummer : LinkdurchläufeMessage=RemovePhoneSuccess
entfernen als Abfragezeichenfolge.
https://localhost:44300/Manage?Message=RemovePhoneSuccess
[]
Die AddPhoneNumber
Aktionsmethode zeigt ein Dialogfeld zum Eingeben einer Telefonnummer an, die SMS-Nachrichten empfangen kann.
// GET: /Account/AddPhoneNumber
public ActionResult AddPhoneNumber()
{
return View();
}
Wenn Sie auf die Schaltfläche Überprüfungscode senden klicken, wird die Telefonnummer an die HTTP POST-Aktionsmethode AddPhoneNumber
gesendet.
// 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 });
}
Die GenerateChangePhoneNumberTokenAsync
-Methode generiert das Sicherheitstoken, das in der SMS-Nachricht festgelegt wird. Wenn der SMS-Dienst konfiguriert wurde, wird das Token als Zeichenfolge "Ihr Sicherheitscode ist <Token>" gesendet. Die SmsService.SendAsync
Methode von wird asynchron aufgerufen, dann wird die App zur VerifyPhoneNumber
Aktionsmethode umgeleitet (in der das folgende Dialogfeld angezeigt wird), wo Sie den Überprüfungscode eingeben können.
Nachdem Sie den Code eingegeben und auf Senden geklickt haben, wird der Code an die HTTP POST-Aktionsmethode VerifyPhoneNumber
gesendet.
// 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);
}
Die ChangePhoneNumberAsync
-Methode überprüft den bereitgestellten Sicherheitscode. Wenn der Code korrekt ist, wird die Telefonnummer dem PhoneNumber
Feld der AspNetUsers
Tabelle hinzugefügt. Wenn dieser Aufruf erfolgreich ist, wird die SignInAsync
-Methode aufgerufen:
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));
}
Der isPersistent
Parameter legt fest, ob die Authentifizierungssitzung über mehrere Anforderungen hinweg beibehalten wird.
Wenn Sie Ihr Sicherheitsprofil ändern, wird ein neuer Sicherheitsstempel generiert und im Feld der SecurityStamp
Tabelle AspNetUsers gespeichert. Beachten Sie, dass sich das SecurityStamp
Feld vom Sicherheitscookies unterscheidet. Das Sicherheitscooky wird nicht in der AspNetUsers
Tabelle (oder an einem anderen Ort in der Identitätsdatenbank) gespeichert. Das Sicherheitscookiestoken wird mithilfe der DPAPI selbstsigniert und mit den Informationen zur UserId, SecurityStamp
Ablaufzeit und erstellt.
Die Cookie-Middleware überprüft das Cookie bei jeder Anforderung. Die SecurityStampValidator
-Methode in der Startup
-Klasse trifft auf die Datenbank und überprüft in regelmäßigen Abständen den Sicherheitsstempel, wie mit angegeben validateInterval
. Dies geschieht nur alle 30 Minuten (in unserem Beispiel), es sei denn, Sie ändern Ihr Sicherheitsprofil. Das Intervall von 30 Minuten wurde gewählt, um Die Fahrten zur Datenbank zu minimieren.
Die SignInAsync
Methode muss aufgerufen werden, wenn änderungen am Sicherheitsprofil vorgenommen werden. Wenn sich das Sicherheitsprofil ändert, aktualisiert die Datenbank das SecurityStamp
Feld, und ohne aufrufen der SignInAsync
Methode bleiben Sie nur angemeldet, bis die OWIN-Pipeline das nächste Mal auf die Datenbank trifft (die validateInterval
). Sie können dies testen, indem Sie die SignInAsync
-Methode so ändern, dass sie sofort zurückgibt, und die Cookie-Eigenschaft validateInterval
von 30 Minuten auf 5 Sekunden festlegen:
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);
Mit den obigen Codeänderungen können Sie Ihr Sicherheitsprofil ändern (z. B. durch Ändern des Status von Zwei Faktor aktiviert), und Sie werden in 5 Sekunden abgemeldet, wenn die SecurityStampValidator.OnValidateIdentity
Methode fehlschlägt. Entfernen Sie die Rückgabezeile in der SignInAsync
-Methode, nehmen Sie eine weitere Änderung des Sicherheitsprofils vor, und Sie werden nicht abgemeldet. Die SignInAsync
Methode generiert ein neues Sicherheitscooky.
Aktivieren Sie die zweistufige Authentifizierung.
In der Beispiel-App müssen Sie die Benutzeroberfläche verwenden, um die zweistufige Authentifizierung (2FA) zu aktivieren. Um 2FA zu aktivieren, klicken Sie in der Navigationsleiste auf Ihre Benutzer-ID (E-Mail-Alias).
Klicken Sie auf 2FA aktivieren. Melden Sie sich ab, und melden Sie sich dann wieder an. Wenn Sie E-Mail aktiviert haben (siehe mein vorheriges Tutorial), können Sie die SMS oder E-Mail für 2FA auswählen. Die Seite Code überprüfen wird angezeigt, auf der Sie den Code (per SMS oder E-Mail) eingeben können. Wenn Sie auf das Kontrollkästchen Diesen Browser speichern klicken, müssen Sie nicht 2FA verwenden, um sich mit diesem Computer und Browser anzumelden. Wenn Sie 2FA aktivieren und auf den Browser speichern klicken, erhalten Sie einen starken 2FA-Schutz vor böswilligen Benutzern, die versuchen, auf Ihr Konto zuzugreifen, solange diese keinen Zugriff auf Ihren Computer haben. Sie können dies auf jedem privaten Computer tun, den Sie regelmäßig verwenden. Durch die Einstellung Diesen Browser speichern erhalten Sie die zusätzliche Sicherheit von 2FA von Computern, die Sie nicht regelmäßig verwenden, und Sie erhalten den Komfort, nicht auf Ihren eigenen Computern 2FA durchlaufen zu müssen.
Registrieren eines Anbieters für die zweistufige Authentifizierung
Wenn Sie ein neues MVC-Projekt erstellen, enthält die Datei IdentityConfig.cs den folgenden Code zum Registrieren eines Anbieters für die zweistufige Authentifizierung:
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;
}
Hinzufügen einer Telefonnummer für 2FA
Die AddPhoneNumber
Aktionsmethode im Manage
Controller generiert ein Sicherheitstoken und sendet es an die angegebene Telefonnummer.
[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 });
}
Nach dem Senden des Tokens wird zur VerifyPhoneNumber
Aktionsmethode weitergeleitet, wo Sie den Code eingeben können, um SMS für 2FA zu registrieren. SMS 2FA wird erst verwendet, wenn Sie die Telefonnummer überprüft haben.
Aktivieren von 2FA
Die EnableTFA
Aktionsmethode aktiviert 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");
}
Beachten Sie, dass SignInAsync
aufgerufen werden muss, da die Aktivierung von 2FA eine Änderung des Sicherheitsprofils ist. Wenn 2FA aktiviert ist, muss der Benutzer 2FA verwenden, um sich mit den registrierten 2FA-Ansätzen anzumelden (SMS und E-Mail im Beispiel).
Sie können weitere 2FA-Anbieter wie QR-Code-Generatoren hinzufügen oder eigene schreiben.
Hinweis
Die 2FA-Codes werden mithilfe des Zeitbasierten Einmalkennwortalgorithmus generiert und sind sechs Minuten gültig. Wenn Sie mehr als sechs Minuten benötigen, um den Code einzugeben, erhalten Sie die Fehlermeldung Ungültiger Code.
Kombinieren von Sozialen und lokalen Anmeldekonten
Sie können lokale und soziale Konten kombinieren, indem Sie auf Ihren E-Mail-Link klicken. In der folgenden Sequenz wird zuerst "RickAndMSFT@gmail.com" als lokaler Anmeldenamen erstellt, aber Sie können das Konto zuerst als Social Media-Anmeldung erstellen und dann eine lokale Anmeldung hinzufügen.
Klicken Sie auf den Link Verwalten . Notieren Sie sich die 0 externen (Social-Media-Anmeldungen), die diesem Konto zugeordnet sind.
Klicken Sie auf den Link zu einem anderen Anmeldedienst, und akzeptieren Sie die App-Anforderungen. Die beiden Konten wurden kombiniert. Sie können sich mit beiden Konten anmelden. Möglicherweise möchten Sie, dass Ihre Benutzer lokale Konten hinzufügen, falls ihr Social-Media-Protokoll im Authentifizierungsdienst ausgefallen ist oder sie wahrscheinlich den Zugriff auf ihr Social Media-Konto verloren haben.
In der folgenden Abbildung handelt es sich bei Tom um ein Social-Media-Log-In (das sehen Sie unter Externe Anmeldungen: 1 auf der Seite).
Wenn Sie auf Kennwort auswählen klicken, können Sie ein lokales Protokoll hinzufügen, das demselben Konto zugeordnet ist.
Kontosperrung vor Brute-Force-Angriffen
Sie können die Konten in Ihrer App vor Wörterbuchangriffen schützen, indem Sie die Benutzersperre aktivieren. Der folgende Code in der ApplicationUserManager Create
-Methode konfiguriert die Sperrung:
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
Der obige Code ermöglicht die Sperrung nur für die zweistufige Authentifizierung. Sie können die Sperrung für Anmeldungen zwar aktivieren, indem Sie in der Login
Methode des Kontocontrollers zu true wechselnshouldLockout
. Es wird jedoch empfohlen, die Sperrung für Anmeldungen nicht zu aktivieren, da das Konto dadurch anfällig für DOS-Anmeldeangriffe ist. Im Beispielcode ist die Sperrung für das mit der ApplicationDbInitializer Seed
-Methode erstellte Administratorkonto deaktiviert:
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);
}
}
Anfordern eines überprüften E-Mail-Kontos für einen Benutzer
Der folgende Code erfordert, dass ein Benutzer über ein überprüftes E-Mail-Konto verfügt, bevor er sich anmelden kann:
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);
}
}
So überprüft SignInManager auf 2FA-Anforderungen
Sowohl das lokale Anmelden als auch das Soziale Anmelden überprüfen, ob 2FA aktiviert ist. Wenn 2FA aktiviert ist, gibt die SignInManager
Anmeldemethode zurück SignInStatus.RequiresVerification
, und der Benutzer wird zur SendCode
Aktionsmethode umgeleitet, wo er den Code eingeben muss, um die Protokollfolge abzuschließen. Wenn der Benutzer RememberMe für das lokale Cookie des Benutzers festgelegt hat, wird SignInStatus.Success
zurückgegebenSignInManager
, und er muss nicht 2FA durchlaufen.
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 });
}
}
Der folgende Code zeigt die SendCode
Aktionsmethode. Ein SelectListItem-Objekt wird erstellt, wobei alle 2FA-Methoden für den Benutzer aktiviert sind. SelectListItem wird an das DropDownListFor-Hilfsprogramm übergeben, sodass der Benutzer den 2FA-Ansatz (in der Regel E-Mail und SMS) auswählen kann.
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 });
}
Sobald der Benutzer den 2FA-Ansatz veröffentlicht, wird die HTTP POST SendCode
Aktionsmethode aufgerufen, sendet SignInManager
den 2FA-Code, und der Benutzer wird zur VerifyCode
Aktionsmethode weitergeleitet, wo er den Code eingeben kann, um die Anmeldung abzuschließen.
//
// 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-Sperrung
Obwohl Sie die Kontosperrung bei Anmeldekennwortversuchsfehlern festlegen können, macht dieser Ansatz Ihre Anmeldung anfällig für DOS-Sperren . Es wird empfohlen, die Kontosperrung nur mit 2FA zu verwenden. Wenn der ApplicationUserManager
erstellt wird, legt der Beispielcode die 2FA-Sperrung auf MaxFailedAccessAttemptsBeforeLockout
fünf fest. Sobald sich ein Benutzer anmeldet (über ein lokales Konto oder ein Soziales Konto), wird jeder fehlgeschlagene 2FA-Versuch gespeichert, und wenn die maximalen Versuche erreicht werden, wird der Benutzer für fünf Minuten gesperrt (Sie können die Sperrzeit mit DefaultAccountLockoutTimeSpan
festlegen).
Zusätzliche Ressourcen
- ASP.NET Der Identität empfohlene Ressourcen Vollständige Liste von Identitätsblogs, Videos, Tutorials und großartigen SO-Links.
- Die MVC 5-App mit Facebook, Twitter, LinkedIn und Google OAuth2 Anmeldung zeigt auch, wie Profilinformationen zur Benutzertabelle hinzugefügt werden.
- ASP.NET MVC und Identität 2.0: Grundlegendes von John Atten.
- Kontobestätigung und Kennwortwiederherstellung mit ASP.NET Identität
- Einführung in ASP.NET Identity
- Ankündigung von RTM von ASP.NET Identity 2.0.0 von Pranav Rastogi.
- ASP.NET Identity 2.0: Einrichten der Kontoüberprüfung und Two-Factor Autorisierung durch John Atten.