ASP.NET Identity 2.0 unterstützt nun die Implementierung von Two-Factor-Authentication-Szenarien. Gemeint ist damit, dass der Benutzer nach der Authentifizierung mit primären Credentials, wie Benutzername und Passwort, durch eine weitere Angabe von Informationen beweisen muss, dass er jener Benutzer ist, der er vorgibt zu sein. Dazu könnte er aufgefordert werden, einen Code, den er per EMail oder SMS erhalten hat, zu erfassen. Informationen dazu findet man unter [1].
Um eine eigene Variante für die Two-Factor-Authentication bereitzustellen, implementiert der Entwickler das Interface IUserTokenProvider<TUser, TKey> (siehe nachfolgendes Listing). Der Typparameter TUser steht dabei für den Typ, mit dem Benutzer repräsentiert werden; TKey für den Typ des Primärschlüssels.
Die aktuell vorliegende BETA von ASP.NET Identity 2.0 bringt zwei Implementierungen dieses Interfaces: Der PhoneNumberTokenProvider versendet einen Code per SMS und der EmailTokenProvider versendet einen Code per EMail.
IUserTokenProvider<TUser, TKey> gibt drei Methoden vor: IsValidProviderForUserAsync , GenerateAsync und ValidateAsync. IsValidProviderForUserAsync prüft, ob die implementierte Two-Factor-Variante für den übergebenen Benutzer durchgeführt werden kann. Der PhoneNumberTokenProvider prüft beispielsweise, ob für den Benutzer eine bestätigte Telefonnummer vorherrscht.
GenerateAsync initiiert die Two-Factor-Authentication, indem es ein Token für den Benutzer generiert. Der PhoneNumberTokenProvider sowie der EmailTokenProvider generieren innerhalb dieser Methode beispielweise einen Code und versenden ihn via SMS bzw. EMail. Um zwischen verschiedenen Gründen für die Generierung des Codes unterscheiden zu können, erhält diese Methode einen String, der über den jeweiligen Grund Auskunft gibt.
ValidateAsync prüft, ob ein vom Benutzer erfasster Code mit der in GenerateAsync generierten Token korreliert.
Die Implementierung im nachfolgenden Listing generiert innerhalb von GenerateAsync eine Rechenaufgabe. Indem der Benutzer diese löst, soll er beweisen, dass er tatsächlich ein menschlicher Benutzer und kein Automatismus ist. Zur Vereinfachung wird diese Rechenaufgabe hier hart codiert und die Speicherung der generierten Aufgabe nur durch ein Kommentar angedeutet. Anschließend retourniert die betrachtete Methode die Rechenaufgabe. ValidateAsync prüft, ob ein korrektes Ergebnis übermittelt wurde und IsValidProviderForUserAsync liefert immer true, da diese Art der Two-Factor-Authentifizierung immer durchgeführt werden kann.
public class CustomUserTokenProvider<TUser, TKey> : IUserTokenProvider<TUser, TKey>
where TUser : class, IUser<TKey>
where TKey : IEquatable<TKey>
{
public System.Threading.Tasks.Task<string> GenerateAsync(string purpose, UserManager<TUser, TKey> manager, TUser user)
{
// Rechenaufgabe erzeugen (zur Vereinfachung statisch)
var challange = "7 + 4";
// Rechenaufgabe in DB für Benutzer hinterlegen
// (hier nicht gezeigt)
return Task.FromResult(challange);
}
public System.Threading.Tasks.Task<bool> ValidateAsync(string purpose, string token, UserManager<TUser, TKey> manager, TUser user)
{
if (token == "11")
{
return Task.FromResult(true);
}
return Task.FromResult(false);
}
public System.Threading.Tasks.Task<bool> IsValidProviderForUserAsync(UserManager<TUser, TKey> manager, TUser user)
{
return Task<bool>.FromResult(true);
}
}
Um den benutzerdefinierten UserTokenProvider zu registrieren, ruft der Entwickler die vom UserManager angebotene Methode RegisterTwoFactorProvider auf. Der erste Parameter repräsentiert den intern zu verwendeten Namen des UserTokenProvider; der zweite eine Instanz davon:
manager.RegisterTwoFactorProvider("Custom", new CustomUserTokenProvider<ApplicationUser, string>());
Der Anwendungscode kann nun die Erstellung eines Tokens mit dem registrierten UserTokenProvider anfordern, in er die vom UserManager angebotene Methode GenerateTwoFactorTokenAsync aufruft, und dabei neben dem Benutzernamen den beim Registrieren definierten internen Namen anführt. Der Rückgabewert von GenerateTwoFactorTokenAsync ist die generierte Rechenaufgabe, welche dem Benutzer anzuzeigen ist:
var challange = await UserManager.GenerateTwoFactorTokenAsync(userId, "Custom");
Dabei muss darauf geachtet warden, dass das Ergebnis von GenerateTwoFactorTokenAsync nicht in jedem Fall dem Benutzer angezeigt werden darf, da – zumindest bei der vorliegenden BETA-Version – diese Methode beim Einsatz des PhoneNumberTokenProviders sowie des EmailTokenProviders den über SMS bzw. EMail versendeten Code retourniert.
Um herauszufinden, ob der Benutzer die Rechenaufgabe korrekt gelöst hat, ruft der Benutzercode die Methode VerifyTwoFactorTokenAsync, welche einen bool retourniert, auf. Dabei übergibt er die UserId, den internen Namen des UserTokenProvider sowie das Ergebnis der Rechenaufgabe:
UserManager.VerifyTwoFactorTokenAsync(user.Id, model.Provider, model.Code)
[1] http://blogs.msdn.com/b/webdev/archive/2014/02/11/announcing-preview-of-microsoft-aspnet-identity-2-0-0-beta1.aspx