ASP.NET Identity で SMS と電子メールを利用して 2 要素認証を行う
作成者: Hao Kung、プラナヴ ラストギ、Rick Anderson、Suhas Joshi
このチュートリアルでは、SMS と電子メールを使用して 2 要素認証 (2FA) を設定する方法について説明します。
この記事は、Rick Anderson (@RickAndMSFT)、プラナヴ ラストギ (@rustd)、Hao Kung、Suhas Joshi によって執筆されました。 NuGet サンプルは、主に Hao Kung によって記述されました。
このトピックでは、以下の内容を説明します。
- ID サンプルのビルド
- 2 要素認証用に SMS を設定する
- 2 要素認証を有効にする
- 2 要素認証プロバイダーを登録する方法
- ソーシャルとローカルのログイン アカウントを結合する
- ブルート フォース攻撃からのアカウント ロックアウト
ID サンプルのビルド
このセクションでは、NuGet を使用して、使用するサンプルをダウンロードします。 まず、Visual Studio Express 2013 for Web または Visual Studio 2013をインストールして実行します。 Visual Studio 2013 Update 2 以降をインストールします。
注意
警告: このチュートリアルを完了するには、Visual Studio 2013 Update 2 をインストールする必要があります。
新しい 空 の ASP.NET Web プロジェクトを作成します。
パッケージ マネージャー コンソールで、次のコマンドを入力します。
Install-Package SendGrid
Install-Package -Prerelease Microsoft.AspNet.Identity.Samples
このチュートリアルでは、 SendGrid を使用してメールを送信し、SMS テキストを送信するために Twilio または ASPSMS を使用します。 このパッケージは
Identity.Samples
、使用するコードをインストールします。SSL を 使用するようにプロジェクトを設定します。
省略可能: Email確認チュートリアルの手順に従って SendGrid をフックし、アプリを実行して電子メール アカウントを登録します。
オプション: サンプルからデモ電子メール リンクの確認コードを削除します (
ViewBag.Link
アカウント コントローラーのコード。DisplayEmail
およびForgotPasswordConfirmation
アクション メソッドと Razor ビューを参照してください。オプション: コードを
ViewBag.Status
管理コントローラーとアカウント コントローラーから削除し、 Views\Account\VerifyCode.cshtml および Views\Manage\VerifyPhoneNumber.cshtml razor ビューから削除します。 または、ディスプレイをViewBag.Status
維持して、このアプリがローカルでどのように動作するかをテストできます。メールや SMS メッセージを接続して送信する必要はありません。
注意
警告: このサンプルのいずれかのセキュリティ設定を変更した場合、運用アプリは、加えられた変更を明示的に呼び出すセキュリティ監査を受ける必要があります。
2 要素認証用に SMS を設定する
このチュートリアルでは、Twilio または ASPSMS を使用する手順を説明しますが、他の SMS プロバイダーを使用できます。
SMS プロバイダーを使用したユーザー アカウントの作成
追加のパッケージのインストールまたはサービス参照の追加
Twilio:
パッケージ マネージャー コンソールで、次のコマンドを入力します。
Install-Package Twilio
ASPSMS:
次のサービス参照を追加する必要があります。Address:
https://webservice.aspsms.com/aspsmsx2.asmx?WSDL
名前空間:
ASPSMSX2
SMS プロバイダーユーザーの資格情報の把握
Twilio:
Twilio アカウントの [ ダッシュボード ] タブから、 アカウント SID と 認証トークンをコピーします。ASPSMS:
アカウント設定から[Userkey]\( ユーザーキー\) に移動し、自己定義パスワードと共にコピー します。これらの値は、後で 変数
SMSAccountIdentification
とSMSAccountPassword
に格納します。SenderID または Originator の指定
Twilio:
[ 番号 ] タブで、Twilio の電話番号をコピーします。ASPSMS:
[ 元のユーザーのロック解除 ] メニューで、1 つ以上の発信元のロックを解除するか、英数字の発信元を選択します (すべてのネットワークでサポートされていません)。この値は後で 変数
SMSAccountFrom
に格納します。SMS プロバイダーの資格情報をアプリに転送する
資格情報と送信者の電話番号をアプリで使用できるようにします。
public static class Keys { public static string SMSAccountIdentification = "My Idenfitication"; public static string SMSAccountPassword = "My Password"; public static string SMSAccountFrom = "+15555551234"; }
警告
セキュリティ - ソース コードに機密データを保存しないでください。 サンプルをシンプルに保つために、アカウントと資格情報が上記のコードに追加されます。 Jon Atten の ASP.NET MVC: ソース管理からプライベート設定を保持するを参照してください。
SMS プロバイダーへのデータ転送の実装
SmsService
App_Start\IdentityConfig.cs ファイルで クラスを構成します。使用されている SMS プロバイダーに応じて、 Twilio または ASPSMS セクションのいずれかをアクティブにします。
public class SmsService : IIdentityMessageService { public Task SendAsync(IdentityMessage message) { // Twilio Begin // var Twilio = new TwilioRestClient( // Keys.SMSAccountIdentification, // Keys.SMSAccountPassword); // var result = Twilio.SendMessage( // Keys.SMSAccountFrom, // message.Destination, message.Body // ); // Status is one of Queued, Sending, Sent, Failed or null if the number is not valid // Trace.TraceInformation(result.Status); // Twilio doesn't currently have an async API, so return success. // return Task.FromResult(0); // Twilio End // ASPSMS Begin // var soapSms = new WebApplication1.ASPSMSX2.ASPSMSX2SoapClient("ASPSMSX2Soap"); // soapSms.SendSimpleTextSMS( // Keys.SMSAccountIdentification, // Keys.SMSAccountPassword, // message.Destination, // Keys.SMSAccountFrom, // message.Body); // soapSms.Close(); // return Task.FromResult(0); // ASPSMS End } }
アプリを実行し、以前に登録したアカウントでログインします。
ユーザー ID をクリックすると、コントローラーで
Manage
アクション メソッドがIndex
アクティブになります。[追加] をクリックします。
数秒後に、確認コードを含むテキスト メッセージが表示されます。 それを入力し、[ 送信] を押します。
[管理] ビューには、電話番号が追加されたことが表示されます。
コードを確認する
// GET: /Account/Index
public async Task<ActionResult> Index(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two factor provider has been set."
: message == ManageMessageId.Error ? "An error has occurred."
: message == ManageMessageId.AddPhoneSuccess ? "The phone number was added."
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
: "";
var model = new IndexViewModel
{
HasPassword = HasPassword(),
PhoneNumber = await UserManager.GetPhoneNumberAsync(User.Identity.GetUserId()),
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(User.Identity.GetUserId()),
Logins = await UserManager.GetLoginsAsync(User.Identity.GetUserId()),
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(User.Identity.GetUserId())
};
return View(model);
}
コントローラーのManage
アクション メソッドはIndex
、以前のアクションに基づいてステータス メッセージを設定し、ローカル パスワードを変更したり、ローカル アカウントを追加したりするためのリンクを提供します。 また、このメソッドは Index
、状態または 2FA 電話番号、外部ログイン、2FA が有効になっている状態を表示し、このブラウザーの 2FA メソッドを記憶します (後で説明します)。 タイトル バーでユーザー ID (電子メール) をクリックしても、メッセージは渡されません。 [ 電話番号: 削除 ] リンクをクリックすると、クエリ文字列としてパスが渡されます Message=RemovePhoneSuccess
。
https://localhost:44300/Manage?Message=RemovePhoneSuccess
[]
アクション メソッドは AddPhoneNumber
、SMS メッセージを受信できる電話番号を入力するダイアログ ボックスを表示します。
// GET: /Account/AddPhoneNumber
public ActionResult AddPhoneNumber()
{
return View();
}
[ 確認コードの送信 ] ボタンをクリックすると、電話番号が HTTP POST AddPhoneNumber
アクション メソッドに投稿されます。
// POST: /Account/AddPhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Generate the token
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(
User.Identity.GetUserId(), model.Number);
if (UserManager.SmsService != null)
{
var message = new IdentityMessage
{
Destination = model.Number,
Body = "Your security code is: " + code
};
// Send token
await UserManager.SmsService.SendAsync(message);
}
return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
}
メソッドは GenerateChangePhoneNumberTokenAsync
、SMS メッセージで設定されるセキュリティ トークンを生成します。 SMS サービスが構成されている場合、トークンは文字列 "Your security code is <token>" として送信されます。 SmsService.SendAsync
の メソッドは非同期的に呼び出され、アプリはアクション メソッド (次のダイアログが表示されます) にリダイレクトされVerifyPhoneNumber
、そこで検証コードを入力できます。
コードを入力して [送信] をクリックすると、コードは HTTP POST VerifyPhoneNumber
アクション メソッドにポストされます。
// POST: /Account/VerifyPhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code);
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess });
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "Failed to verify phone");
return View(model);
}
メソッドは ChangePhoneNumberAsync
、投稿されたセキュリティ コードをチェックします。 コードが正しい場合は、電話番号がテーブルのフィールドにPhoneNumber
AspNetUsers
追加されます。 その呼び出しが成功した場合、 SignInAsync
メソッドは次のように呼び出されます。
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
// Clear the temporary cookies used for external and two factor sign ins
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie,
DefaultAuthenticationTypes.TwoFactorCookie);
AuthenticationManager.SignIn(new AuthenticationProperties
{
IsPersistent = isPersistent
},
await user.GenerateUserIdentityAsync(UserManager));
}
パラメーターは isPersistent
、認証セッションを複数の要求にわたって保持するかどうかを設定します。
セキュリティ プロファイルを変更すると、新しいセキュリティ スタンプが生成され、AspNetUsers テーブルの フィールドに格納されますSecurityStamp
。 フィールドは SecurityStamp
セキュリティ Cookie とは異なります。 セキュリティ Cookie は、テーブル (または Identity DB 内の他の場所) に格納 AspNetUsers
されません。 セキュリティ Cookie トークンは DPAPI を使用して自己署名され、 と の有効期限情報を UserId, SecurityStamp
使用して作成されます。
Cookie ミドルウェアは、各要求で Cookie をチェックします。 クラスの メソッドは SecurityStampValidator
DB にヒットし、 で指定されているように、定期的にセキュリティ スタンプをチェックしますvalidateInterval
。Startup
これは、セキュリティ プロファイルを変更しない限り、(サンプルでは) 30 分ごとに発生します。 データベースへの乗車を最小限に抑えるために、30 分の間隔が選択されました。
SignInAsync
セキュリティ プロファイルに変更が加えられた場合は、 メソッドを呼び出す必要があります。 セキュリティ プロファイルが変更されると、データベースは フィールドをSecurityStamp
更新します。メソッドをSignInAsync
呼び出さずに、OWIN パイプラインが次にデータベース (validateInterval
) にヒットするまでログインし続けます。 これをテストするには、 メソッドを SignInAsync
変更してすぐに返し、cookie validateInterval
プロパティを 30 分から 5 秒に設定します。
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
return;
// Clear any partial cookies from external or two factor partial sign ins
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie,
DefaultAuthenticationTypes.TwoFactorCookie);
AuthenticationManager.SignIn(new AuthenticationProperties
{
IsPersistent = isPersistent
},
await user.GenerateUserIdentityAsync(UserManager));
}
public void ConfigureAuth(IAppBuilder app) {
// Configure the db context, user manager and role manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a
// third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider {
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add
// an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
//validateInterval: TimeSpan.FromMinutes(30),
validateInterval: TimeSpan.FromSeconds(5),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
上記のコードが変更されると、セキュリティ プロファイルを変更できます (たとえば、 Two Factor Enabled の状態を変更するなど)。 メソッドが失敗すると SecurityStampValidator.OnValidateIdentity
、5 秒でログアウトされます。 メソッドの戻り行を SignInAsync
削除し、別のセキュリティ プロファイルを変更すると、ログアウトされません。メソッドは SignInAsync
、新しいセキュリティ Cookie を生成します。
2 要素認証を有効にする
サンプル アプリでは、UI を使用して 2 要素認証 (2FA) を有効にする必要があります。 2FA を有効にするには、ナビゲーション バーでユーザー ID (電子メール エイリアス) をクリックします。
[2FA を有効にする] をクリックします。 ログアウトしてから、再度ログインします。 メールを有効にしている場合 (前の チュートリアルを参照)、2FA の SMS またはメールを選択できます。 [コードの確認] ページが表示され、ここで (SMS または電子メールから) コードを入力できます。[このブラウザーを記憶するチェック] ボックスをクリックすると、2FA を使用してそのコンピューターとブラウザーでログオンする必要が除外されます。 2FAを有効にして[ このブラウザを記憶 する]をクリックすると、コンピュータにアクセスできない限り、アカウントにアクセスしようとしている悪意のあるユーザーからの強力な2FA保護が提供されます。 これは、定期的に使用する任意のプライベート マシンで行うことができます。 [このブラウザーを記憶する] を設定すると、定期的に使用しないコンピューターから 2FA のセキュリティが強化され、自分のコンピューターで 2FA を使用する必要がないという利便性が得られます。
2 要素認証プロバイダーを登録する方法
新しい MVC プロジェクトを作成すると、 IdentityConfig.cs ファイルには、2 要素認証プロバイダーを登録するための次のコードが含まれます。
public static ApplicationUserManager Create(
IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var manager = new ApplicationUserManager(
new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// Register two factor authentication providers. This application uses Phone and Emails as a
// step of receiving a code for verifying the user
// You can write your own provider and plug it in here.
manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Your security code is: {0}"
});
manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is: {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>
(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
2FA の電話番号を追加する
コントローラーのManage
アクション メソッドはAddPhoneNumber
、セキュリティ トークンを生成し、指定した電話番号に送信します。
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Generate the token and send it
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(
User.Identity.GetUserId(), model.Number);
if (UserManager.SmsService != null)
{
var message = new IdentityMessage
{
Destination = model.Number,
Body = "Your security code is: " + code
};
await UserManager.SmsService.SendAsync(message);
}
return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
}
トークンを送信すると、アクション メソッドに VerifyPhoneNumber
リダイレクトされます。ここで、2FA の SMS を登録するコードを入力できます。 SMS 2FA は、電話番号を確認するまで使用されません。
2FA の有効化
アクション メソッドでは EnableTFA
、次の 2FA が有効になります。
// POST: /Manage/EnableTFA
[HttpPost]
public async Task<ActionResult> EnableTFA()
{
await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
return RedirectToAction("Index", "Manage");
}
SignInAsync
enable 2FA はセキュリティ プロファイルの変更であるため、 を呼び出す必要があることに注意してください。 2FA が有効になっている場合、ユーザーは登録した 2FA アプローチ (サンプルの SMS と電子メール) を使用して、2FA を使用してログインする必要があります。
QR コード ジェネレーターなどの 2FA プロバイダーをさらに追加することも、独自のプロバイダーを作成することもできます。
注意
2FA コードは 、時間ベースのワンタイム パスワード アルゴリズム を使用して生成され、コードは 6 分間有効です。 コードの入力に 6 分以上かかる場合は、無効なコード エラー メッセージが表示されます。
ソーシャルとローカルのログイン アカウントを結合する
メールのリンクをクリックして、ローカル アカウントとソーシャル アカウントを組み合わせることができます。 次のシーケンスでは、最初に "RickAndMSFT@gmail.com" がローカル ログインとして作成されますが、最初にソーシャル ログとしてアカウントを作成してから、ローカル ログインを追加できます。
[管理] リンクをクリックします。 このアカウントに関連付けられている外部 (ソーシャル ログイン) が 0 であることに注意してください。
別のログイン サービスへのリンクをクリックし、アプリの要求を受け入れます。 2 つのアカウントが組み合わされているため、どちらのアカウントでもログオンできます。 認証サービスのソーシャル ログがダウンした場合や、ソーシャル アカウントへのアクセスが失われた可能性が高い場合に備えて、ユーザーにローカル アカウントを追加することが必要な場合があります。
次の図では、Tom はソーシャル ログインです (ページに表示されている 外部ログイン: 1 から確認できます)。
[パスワードの 選択 ] をクリックすると、同じアカウントに関連付けられているローカル ログオンを追加できます。
ブルート フォース攻撃からのアカウント ロックアウト
ユーザー ロックアウトを有効にすることで、辞書攻撃からアプリのアカウントを保護できます。 メソッドの次のコードは ApplicationUserManager Create
、ロックアウトを構成します。
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
上記のコードでは、2 要素認証に対してのみロックアウトが有効になります。 アカウント コントローラーのメソッドで Login
true に変更shouldLockout
することでログインのロックアウトを有効にすることができますが、アカウントが DOS ログイン攻撃の影響を受けやすくなるため、ログインのロックアウトを有効にしないことをお勧めします。 サンプル コードでは、 メソッドで ApplicationDbInitializer Seed
作成された管理者アカウントのロックアウトが無効になっています。
public static void InitializeIdentityForEF(ApplicationDbContext db)
{
var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
const string name = "admin@example.com";
const string roleName = "Admin";
//Create Role Admin if it does not exist
var role = roleManager.FindByName(roleName);
if (role == null)
{
role = new IdentityRole(roleName);
var roleresult = roleManager.Create(role);
}
var user = userManager.FindByName(name);
if (user == null)
{
user = new ApplicationUser { UserName = name, Email = name };
var result = userManager.Create(user, GetSecurePassword());
result = userManager.SetLockoutEnabled(user.Id, false);
}
// Add user admin to Role Admin if not already added
var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name))
{
var result = userManager.AddToRole(user.Id, role.Name);
}
}
検証済みの電子メール アカウントをユーザーに要求する
次のコードでは、ユーザーがログインする前に、検証済みの電子メール アカウントを持っている必要があります。
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Require the user to have a confirmed email before they can log on.
var user = await UserManager.FindByNameAsync(model.Email);
if (user != null)
{
if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
ViewBag.errorMessage = "You must have a confirmed email to log on.";
return View("Error");
}
}
// This doen't count login failures towards lockout only two factor authentication
// To enable password failures to trigger lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password,
model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
SignInManager が 2FA 要件を確認する方法
ローカル ログインとソーシャル ログインの両方チェック、2FA が有効になっているかどうかを確認します。 2FA が有効になっている場合、 SignInManager
ログオン メソッドは を返 SignInStatus.RequiresVerification
し、ユーザーはアクション メソッドに SendCode
リダイレクトされます。ここで、ログインシーケンスを完了するにはコードを入力する必要があります。 ユーザーがユーザーのローカル Cookie に RememberMe が設定されている場合は、 SignInManager
が返 SignInStatus.Success
され、2FA を経由する必要はありません。
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Require the user to have a confirmed email before they can log on.
var user = await UserManager.FindByNameAsync(model.Email);
if (user != null)
{
if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
ViewBag.errorMessage = "You must have a confirmed email to log on.";
return View("Error");
}
}
// This doen't count login failures towards lockout only two factor authentication
// To enable password failures to trigger lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password,
model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
// Sign in the user with this external login provider if the user already has a login
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
case SignInStatus.Failure:
default:
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
}
}
次のコードは、アクション メソッドを SendCode
示しています。 SelectListItem は、ユーザーに対して有効になっているすべての 2FA メソッドで作成されます。 SelectListItem は DropDownListFor ヘルパーに渡されます。これにより、ユーザーは 2FA アプローチ (通常はメールと 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 });
}
ユーザーが 2FA アプローチを投稿すると、 HTTP POST SendCode
アクション メソッドが呼び出され、 SignInManager
2FA コードが送信され、ユーザーはアクション メソッドに VerifyCode
リダイレクトされ、そこでコードを入力してログインを完了できます。
//
// POST: /Account/SendCode
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SendCode(SendCodeViewModel model)
{
if (!ModelState.IsValid)
{
return View();
}
// Generate the token and send it
if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider))
{
return View("Error");
}
return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl });
}
2FA ロックアウト
ログイン パスワードの試行エラーにアカウント ロックアウトを設定できますが、この方法では、ログインが DOS ロックアウトの影響を受けやすくなります。 アカウントロックアウトは 2FA でのみ使用することをお勧めします。 が ApplicationUserManager
作成されると、サンプル コードは 2FA ロックアウトと MaxFailedAccessAttemptsBeforeLockout
5 を設定します。 ユーザーが (ローカル アカウントまたはソーシャル アカウントを使用して) ログインすると、2FA で失敗した試行が格納され、最大試行回数に達すると、ユーザーは 5 分間ロックアウトされます (でロックアウト時間 DefaultAccountLockoutTimeSpan
を設定できます)。
その他のリソース
- ASP.NET ID に関する推奨リソース ID ブログ、ビデオ、チュートリアル、優れた SO リンクの完全な一覧。
- Facebook、Twitter、LinkedIn、Google OAuth2 のサインオンを使用した MVC 5 アプリでは、 ユーザー テーブルにプロファイル情報を追加する方法も示されています。
- ASP.NET MVC と ID 2.0: John Atten による基本の理解。
- ASP.NET ID を使用したアカウントの確認とパスワードの回復
- ASP.NET Identity 入門
- プラナヴ・ラストギによる ASP.NET Identity 2.0.0 の RTM の発表。
- ASP.NET ID 2.0: John Atten によるアカウント検証とTwo-Factor承認の設定 。
フィードバック
https://aka.ms/ContentUserFeedback。
近日公開予定: 2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub イシューを段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、以下を参照してください:フィードバックの送信と表示