Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Przez Hao Kung, Pranav Rastogi, Rick Anderson, Suhas Joshi
W tym samouczku pokazano, jak skonfigurować uwierzytelnianie dwuskładnikowe (2FA) przy użyciu wiadomości SMS i poczty e-mail.
Ten artykuł został napisany przez Ricka Andersona (@RickAndMSFT), Pranav Rastogi (@rustd), Hao Kung i Suhas Joshi. Przykład NuGet został napisany głównie przez Hao Kung.
W tym temacie omówiono następujące kwestie:
- Kompilowanie przykładu Identity
- Konfigurowanie programu SMS na potrzeby uwierzytelniania dwuskładnikowego
- Włączanie uwierzytelniania dwuskładnikowego
- Jak zarejestrować dostawcę uwierzytelniania dwuskładnikowego
- Łączenie kont logowania społecznościowego i lokalnego
- Blokada konta przed atakami siłowymi
Kompilowanie przykładu Identity
W tej sekcji użyjesz narzędzia NuGet, aby pobrać przykład, z którym będziemy pracować. Rozpocznij od zainstalowania i uruchomienia Visual Studio Express 2013 dla sieci Web lub Visual Studio 2013. Zainstaluj program Visual Studio 2013 Update 2 lub nowszy.
Uwaga
Ostrzeżenie: Aby ukończyć ten samouczek, musisz zainstalować program Visual Studio 2013 Update 2 .
Utwórz nowy pusty projekt ASP.NET sieci Web.
W konsoli Menedżera pakietów wprowadź następujące polecenia:
Install-Package SendGrid
Install-Package -Prerelease Microsoft.AspNet.Identity.Samples
W tym samouczku użyjemy usługi SendGrid do wysyłania wiadomości e-mail i usługi Twilio lub ASPSMS na potrzeby sms-ów. Pakiet
Identity.Samples
instaluje kod, z którym będziemy pracować.Opcjonalnie: postępuj zgodnie z instrukcjami w samouczku z potwierdzeniem Email, aby podłączyć usługę SendGrid, a następnie uruchomić aplikację i zarejestrować konto e-mail.
Opcjonalne: Usuń kod potwierdzenia linku demonstracyjnego wiadomości e-mail z przykładu (
ViewBag.Link
kod w kontrolerze konta.DisplayEmail
Zobacz metody iForgotPasswordConfirmation
akcji i widoki razor ).Opcjonalne:
ViewBag.Status
Usuń kod z kontrolerów zarządzanie i konta oraz z widoków Views\Account\VerifyCode.cshtml i Views\Manage\VerifyPhoneNumber.cshtml razor views. Możesz też zachowaćViewBag.Status
wyświetlanie, aby przetestować sposób działania tej aplikacji lokalnie bez konieczności podłączania i wysyłania wiadomości e-mail i wiadomości SMS.
Uwaga
Ostrzeżenie: Jeśli zmienisz dowolne ustawienia zabezpieczeń w tym przykładzie, aplikacje produkcyjne będą musiały przejść inspekcję zabezpieczeń, która jawnie wywołuje wprowadzone zmiany.
Konfigurowanie programu SMS na potrzeby uwierzytelniania dwuskładnikowego
Ten samouczek zawiera instrukcje dotyczące korzystania z usługi Twilio lub ASPSMS, ale możesz użyć dowolnego innego dostawcy programu SMS.
Tworzenie konta użytkownika za pomocą dostawcy programu SMS
Utwórz konto usługi Twilio lub asPSMS .
Instalowanie dodatkowych pakietów lub dodawanie odwołań do usługi
Twilio:
W konsoli Menedżera pakietów wprowadź następujące polecenie:
Install-Package Twilio
ASPSMS:
Należy dodać następujące odwołanie do usługi:Adres:
https://webservice.aspsms.com/aspsmsx2.asmx?WSDL
Przestrzeń nazw:
ASPSMSX2
Określanie poświadczeń użytkownika dostawcy programu SMS
Twilio:
Na karcie Pulpit nawigacyjny konta usługi Twilio skopiuj identyfikator SID konta i token uwierzytelniania.ASPSMS:
W ustawieniach konta przejdź do pozycji Userkey i skopiuj je wraz z własnym hasłem.Te wartości zostaną później przechowywane w zmiennych
SMSAccountIdentification
iSMSAccountPassword
.Określanie identyfikatora nadawcy/elementu źródłowego
Twilio:
Na karcie Numery skopiuj swój numer telefonu usługi Twilio.ASPSMS:
W menu Odblokuj elementy źródłowe odblokuj co najmniej jedną jednostkę źródłową lub wybierz alfanumeryczną jednostkę źródłową (nieobsługiwana przez wszystkie sieci).Później zapiszemy tę wartość w zmiennej
SMSAccountFrom
.Przenoszenie poświadczeń dostawcy programu SMS do aplikacji
Podaj poświadczenia i numer telefonu nadawcy w aplikacji:
public static class Keys { public static string SMSAccountIdentification = "My Idenfitication"; public static string SMSAccountPassword = "My Password"; public static string SMSAccountFrom = "+15555551234"; }
Ostrzeżenie
Zabezpieczenia — nigdy nie przechowuj poufnych danych w kodzie źródłowym. Konto i poświadczenia są dodawane do powyższego kodu, aby zachować prosty przykład. Zobacz ASP.NET MVC Jona Attena : Zachowaj ustawienia prywatne poza kontrolą źródła.
Implementacja transferu danych do dostawcy programu SMS
Skonfiguruj klasę
SmsService
w pliku App_Start\IdentityConfig.cs .W zależności od używanego dostawcy programu SMS aktywuj usługę Twilio lub sekcję 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 } }
Uruchom aplikację i zaloguj się przy użyciu wcześniej zarejestrowanego konta.
Kliknij swój identyfikator użytkownika, który aktywuje metodę
Index
akcji wManage
kontrolerze.Kliknij pozycję Add (Dodaj).
W ciągu kilku sekund otrzymasz wiadomość SMS z kodem weryfikacyjnym. Wprowadź go i naciśnij przycisk Prześlij.
Widok Zarządzaj pokazuje, że numer telefonu został dodany.
Analizowanie kodu
// 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);
}
Metoda Index
akcji w Manage
kontrolerze ustawia komunikat o stanie na podstawie poprzedniej akcji i udostępnia linki do zmiany hasła lokalnego lub dodania konta lokalnego. Metoda Index
wyświetla również stan lub numer telefonu 2FA, identyfikatory logowania zewnętrzne, włączoną uwierzytelnianie 2FA i zapamiętaj metodę 2FA dla tej przeglądarki (wyjaśnij później). Kliknięcie identyfikatora użytkownika (e-mail) na pasku tytułu nie przekazuje wiadomości. Kliknięcie linku Numer telefonu: usuń przekazuje Message=RemovePhoneSuccess
link jako ciąg zapytania.
https://localhost:44300/Manage?Message=RemovePhoneSuccess
[]
Metoda AddPhoneNumber
akcji wyświetla okno dialogowe, aby wprowadzić numer telefonu, który może odbierać wiadomości SMS.
// GET: /Account/AddPhoneNumber
public ActionResult AddPhoneNumber()
{
return View();
}
Kliknięcie przycisku Wyślij kod weryfikacyjny powoduje opublikowanie numeru telefonu do metody akcji 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 });
}
Metoda GenerateChangePhoneNumberTokenAsync
generuje token zabezpieczający, który zostanie ustawiony w wiadomości SMS. Jeśli usługa SMS została skonfigurowana, token jest wysyłany jako ciąg "Twój kod zabezpieczeń jest <tokenem>".
SmsService.SendAsync
Metoda do jest wywoływana asynchronicznie, a następnie aplikacja jest przekierowywana do VerifyPhoneNumber
metody akcji (która wyświetla następujące okno dialogowe), gdzie można wprowadzić kod weryfikacyjny.
Po wprowadzeniu kodu i kliknięciu przycisku prześlij kod zostanie opublikowany w metodzie akcji 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);
}
Metoda ChangePhoneNumberAsync
sprawdza opublikowany kod zabezpieczeń. Jeśli kod jest poprawny, numer telefonu jest dodawany do PhoneNumber
pola AspNetUsers
tabeli. Jeśli to wywołanie powiedzie się, metoda jest wywoływana 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));
}
Parametr określa, czy sesja isPersistent
uwierzytelniania jest utrwalana w wielu żądaniach.
Po zmianie profilu zabezpieczeń zostanie wygenerowana nowa sygnatura zabezpieczeń i zapisana w SecurityStamp
polu tabeli AspNetUsers . Uwaga: SecurityStamp
pole różni się od pliku cookie zabezpieczeń. Plik cookie zabezpieczeń nie jest przechowywany w AspNetUsers
tabeli (ani nigdzie indziej w bazie danych tożsamości). Token pliku cookie zabezpieczeń jest podpisany samodzielnie przy użyciu interfejsu UserId, SecurityStamp
DPAPI i jest tworzony przy użyciu informacji o czasie wygaśnięcia i .
Oprogramowanie pośredniczące pliku cookie sprawdza plik cookie na każdym żądaniu. Metoda SecurityStampValidator
w Startup
klasie okresowo sprawdza bazę danych i sprawdza sygnaturę zabezpieczeń zgodnie z parametrem validateInterval
. Dzieje się to tylko co 30 minut (w naszym przykładzie), chyba że zmienisz profil zabezpieczeń. Wybrano 30-minutowy interwał, aby zminimalizować podróże do bazy danych.
Metoda SignInAsync
musi zostać wywołana po wprowadzeniu dowolnej zmiany w profilu zabezpieczeń. Gdy profil zabezpieczeń ulegnie zmianie, baza danych zostanie zaktualizowana SecurityStamp
w polu i bez wywołania SignInAsync
metody zostanie zalogowana tylko do momentu następnego trafienia potoku OWIN do bazy danych ().validateInterval
Można to przetestować, zmieniając metodę SignInAsync
, aby zwracać natychmiast, i ustawiając właściwość pliku cookie validateInterval
z 30 minut na 5 sekund:
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);
Po wprowadzeniu powyższych zmian w kodzie można zmienić profil zabezpieczeń (na przykład przez zmianę stanu Włączone dwa czynniki) i wylogować się w ciągu 5 sekund, gdy SecurityStampValidator.OnValidateIdentity
metoda zakończy się niepowodzeniem. Usuń wiersz zwrotny w metodzie SignInAsync
, wprowadź inną zmianę profilu zabezpieczeń i nie zostanie wylogowany. Metoda SignInAsync
generuje nowy plik cookie zabezpieczeń.
Włącz uwierzytelnianie dwuskładnikowe
W przykładowej aplikacji musisz użyć interfejsu użytkownika, aby włączyć uwierzytelnianie dwuskładnikowe (2FA). Aby włączyć uwierzytelnianie 2FA, kliknij swój identyfikator użytkownika (alias adresu e-mail) na pasku nawigacyjnym.
Kliknij pozycję Włącz uwierzytelnianie 2FA.
Wyloguj się, a następnie zaloguj się ponownie. Jeśli włączono pocztę e-mail (zobacz mój poprzedni samouczek), możesz wybrać wiadomość SMS lub wiadomość e-mail dla uwierzytelniania 2FA.
Zostanie wyświetlona strona Weryfikuj kod, na której można wprowadzić kod (z wiadomości SMS lub wiadomości e-mail).
Kliknięcie pola wyboru Zapamiętaj tę przeglądarkę spowoduje wykluczenie konieczności użycia uwierzytelniania 2FA do zalogowania się na tym komputerze i w przeglądarce. Włączenie uwierzytelniania 2FA i kliknięcie przycisku Zapamiętaj tę przeglądarkę zapewni silną ochronę 2FA przed złośliwymi użytkownikami próbującymi uzyskać dostęp do konta, o ile nie mają dostępu do komputera. Można to zrobić na dowolnej maszynie prywatnej, której regularnie używasz. Ustawiając ustawienie Zapamiętaj tę przeglądarkę, uzyskujesz dodatkowe zabezpieczenia uwierzytelniania 2FA z komputerów, które nie są regularnie używane, i wygoda w przypadku braku konieczności przechodzenia przez uwierzytelnianie 2FA na własnych komputerach.
Jak zarejestrować dostawcę uwierzytelniania dwuskładnikowego
Podczas tworzenia nowego projektu MVC plik IdentityConfig.cs zawiera następujący kod umożliwiający zarejestrowanie dostawcy uwierzytelniania dwuskładnikowego:
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;
}
Dodawanie numeru telefonu dla uwierzytelniania 2FA
AddPhoneNumber
Metoda akcji w kontrolerze Manage
generuje token zabezpieczający i wysyła go do podanego numeru telefonu.
[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 });
}
Po wysłaniu tokenu nastąpi przekierowanie do VerifyPhoneNumber
metody akcji, w której można wprowadzić kod w celu zarejestrowania wiadomości SMS na potrzeby 2FA. Uwierzytelnianie SMS 2FA nie jest używane do momentu zweryfikowania numeru telefonu.
Włączanie uwierzytelniania 2FA
EnableTFA
Metoda akcji włącza uwierzytelnianie 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");
}
Należy pamiętać, że element musi być wywoływany SignInAsync
, ponieważ włączenie uwierzytelniania 2FA jest zmianą profilu zabezpieczeń. Po włączeniu uwierzytelniania 2FA użytkownik będzie musiał zalogować się przy użyciu uwierzytelniania 2FA, korzystając z metod uwierzytelniania 2FA zarejestrowanych (wiadomości SMS i wiadomości e-mail w przykładzie).
Możesz dodać więcej dostawców uwierzytelniania 2FA, takich jak generatory kodu QR, lub napisać własne.
Uwaga
Kody 2FA są generowane przy użyciu jednorazowego algorytmu haseł opartego na czasie , a kody są ważne przez sześć minut. Jeśli wprowadzenie kodu potrwa dłużej niż sześć minut, zostanie wyświetlony komunikat o błędzie Nieprawidłowy kod.
Łączenie kont logowania społecznościowego i lokalnego
Możesz połączyć konta lokalne i społecznościowe, klikając link do poczty e-mail. W poniższej sekwencji "RickAndMSFT@gmail.com" najpierw jest tworzony jako identyfikator logowania lokalnego, ale najpierw możesz utworzyć konto jako dziennik społecznościowy, a następnie dodać lokalne dane logowania.
Kliknij link Zarządzaj . Zwróć uwagę na 0 zewnętrznych (identyfikatorów logowania społecznościowego) skojarzonych z tym kontem.
Kliknij link do innej usługi logowania i zaakceptuj żądania aplikacji. Te dwa konta zostały połączone. Możesz zalogować się przy użyciu jednego z tych kont. Możesz chcieć, aby użytkownicy dodawali konta lokalne na wypadek awarii usługi uwierzytelniania w sieci społecznościowej lub prawdopodobnie utracili dostęp do konta społecznościowego.
Na poniższej ilustracji Tom jest dziennikiem społecznościowym (widocznym na stronie są dane logowania zewnętrzne: 1 ).
Kliknięcie pozycji Wybierz hasło umożliwia dodanie lokalnego logowania skojarzonego z tym samym kontem.
Blokada konta przed atakami siłowymi
Konta w aplikacji można chronić przed atakami słownika, włączając blokadę użytkownika. Poniższy kod w metodzie ApplicationUserManager Create
konfiguruje blokadę:
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
Powyższy kod włącza blokadę tylko dla uwierzytelniania dwuskładnikowego. Chociaż możesz włączyć blokadę dla logowań, zmieniając wartość shouldLockout
na true w Login
metodzie kontrolera konta, zalecamy, aby nie włączać blokady dla logowań, ponieważ powoduje to, że konto jest podatne na ataki logowania do systemu DOS . W przykładowym kodzie blokada jest wyłączona dla konta administratora utworzonego w metodzie 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);
}
}
Wymaganie od użytkownika posiadania zweryfikowanego konta e-mail
Poniższy kod wymaga, aby użytkownik miał zweryfikowane konto e-mail, zanim będzie mógł się zalogować:
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);
}
}
Jak narzędzie SignInManager sprawdza wymaganie uwierzytelniania 2FA
Zarówno logowanie lokalne, jak i logowanie społecznościowe są sprawdzane, czy włączono uwierzytelnianie 2FA. Jeśli uwierzytelnianie 2FA jest włączone, SignInManager
metoda logowania zwraca SignInStatus.RequiresVerification
wartość , a użytkownik zostanie przekierowany do SendCode
metody akcji, gdzie będzie musiał wprowadzić kod w celu ukończenia logowania w sekwencji. Jeśli użytkownik ma ustawienie RememberMe na lokalnym pliku cookie użytkowników, zostanie zwrócony SignInManager
SignInStatus.Success
i nie będzie musiał przechodzić przez 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 });
}
}
Poniższy kod przedstawia metodę SendCode
akcji. Element SelectListItem jest tworzony ze wszystkimi metodami 2FA włączonymi dla użytkownika. Element SelectListItem jest przekazywany do pomocnika DropDownListFor , który umożliwia użytkownikowi wybranie podejścia 2FA (zazwyczaj wiadomości e-mail i wiadomości SMS).
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 });
}
Gdy użytkownik opublikuje metodę 2FA, wywoływana jest metoda akcji, SignInManager
wysyła kod 2FA, a użytkownik jest przekierowywany do VerifyCode
metody akcji, HTTP POST SendCode
w której może wprowadzić kod w celu ukończenia logowania.
//
// 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 });
}
Blokada 2FA
Mimo że można ustawić blokadę konta w przypadku niepowodzeń prób logowania, takie podejście sprawia, że logowanie jest podatne na blokady systemu DOS . Zalecamy używanie blokady konta tylko z uwierzytelnianiem 2FA. Po utworzeniu ApplicationUserManager
przykładowy kod ustawia blokadę 2FA i MaxFailedAccessAttemptsBeforeLockout
na pięć. Po zalogowaniu się użytkownika (za pośrednictwem konta lokalnego lub konta społecznościowego) każda nieudana próba 2FA jest przechowywana i jeśli zostanie osiągnięta maksymalna liczba prób, użytkownik zostanie zablokowany przez pięć minut (możesz ustawić czas blokady za DefaultAccountLockoutTimeSpan
pomocą polecenia ).
Dodatkowe zasoby
- zalecane zasoby dotyczące tożsamości ASP.NET Pełna lista blogów tożsamości, filmów wideo, samouczków i doskonałych linków SO.
- Aplikacja MVC 5 z usługami Facebook, Twitter, LinkedIn i Google OAuth2 Sign-on pokazuje również, jak dodać informacje o profilu do tabeli użytkowników.
- ASP.NET MVC i Identity 2.0: Omówienie podstaw autorstwa Johna Attena.
- Potwierdzenie konta i odzyskiwanie hasła przy użyciu tożsamości ASP.NET
- Wprowadzenie do systemu ASP.NET Identity
- Ogłoszenie RTM ASP.NET Identity 2.0.0 przez Pranav Rastogi.
- ASP.NET Identity 2.0: Konfigurowanie weryfikacji konta i autoryzacji Two-Factor przez Johna Attena.