Freigeben über


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

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.

  1. Erstellen Sie ein neues leeres ASP.NET Webprojekt.

  2. 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.

  3. Legen Sie das Projekt so fest, dass SSL verwendet wird.

  4. 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.

  5. 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 den DisplayEmail Aktionsmethoden und ForgotPasswordConfirmation razor-Ansichten .

  6. 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 die ViewBag.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.

  1. Erstellen eines Benutzerkontos mit einem SMS-Anbieter

    Erstellen Sie ein Twilio - oder ASPSMS-Konto .

  2. 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:

    Abbildung des Fensters

    Adresse:
    https://webservice.aspsms.com/aspsmsx2.asmx?WSDL

    Namespace:
    ASPSMSX2

  3. 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 und SMSAccountPassword gespeichert.

  4. 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.

  5. Ü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.

  6. 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
        }
    }
    
  7. Führen Sie die App aus, und melden Sie sich mit dem Konto an, das Sie zuvor registriert haben.

  8. Klicken Sie auf Ihre Benutzer-ID, wodurch die Index Aktionsmethode im Manage Controller aktiviert wird.

    Abbildung des registrierten Kontos, das bei der App angemeldet ist

  9. Klicken Sie auf Hinzufügen.

    Abbildung des Links

  10. In wenigen Sekunden erhalten Sie eine SMS mit dem Überprüfungscode. Geben Sie es ein, und drücken Sie Senden.

    Abbildung, die den Codeeintrag für die Telefonüberprüfung zeigt

  11. Die Ansicht Verwalten zeigt, dass Ihre Telefonnummer hinzugefügt wurde.

    Abbildung des Fensters

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

[Bild der Telefonnummer entfernt]

Die AddPhoneNumber Aktionsmethode zeigt ein Dialogfeld zum Eingeben einer Telefonnummer an, die SMS-Nachrichten empfangen kann.

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

Abbildung des Dialogfelds

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.

Abbildung des Dialogfelds

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 SecurityStampTabelle 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). Abbildung von U I zum Aktivieren der zweistufigen Authentifizierung
Klicken Sie auf 2FA aktivieren.Abbildung nach dem Klicken auf Benutzer-ID mit Link zum Aktivieren der zweistufigen Authentifizierung 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.Abbildung mit Optionen zum Senden von Überprüfungen Die Seite Code überprüfen wird angezeigt, auf der Sie den Code (per SMS oder E-Mail) eingeben können.Abbildung der Codeseite 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.

Bild, das E-Mail-Link auswählt

Klicken Sie auf den Link Verwalten . Notieren Sie sich die 0 externen (Social-Media-Anmeldungen), die diesem Konto zugeordnet sind.

Bild, das die nächste Seite zeigt und

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).

Abbildung, die externe Anmeldungen und den Speicherort der Kennwortauswahl zeigt

Wenn Sie auf Kennwort auswählen klicken, können Sie ein lokales Protokoll hinzufügen, das demselben Konto zugeordnet ist.

Abbildung der Seite

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 DefaultAccountLockoutTimeSpanfestlegen).

Zusätzliche Ressourcen