パスワードの検証強化
ASP.NET Identity 1.0では、ユーザー登録時に設定するパスワードの妥当性は、標準では文字長しかチェックされませんでした。ASP.NET Identity 2.0では、新たにMicrosoft.AspNet.Identity.PasswordValidatorクラスが追加され、さまざまなチェックを行えるようになりました。
PasswordValidatorクラスはUserValidator<TUser>クラスと同じく、IIdentityValidator<T>クラスの派生クラスです。ユーザー名のチェック方法指定と同様に、IdentityConfig.csファイルに定義されたApplicationUserクラスのCreateメソッドで、UserManagerクラスのPasswordValidatorプロパティに設定されます(リスト3)。
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
...
// パスワードの検証ロジックを設定します
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
}
}
PassworkValidatorクラスでは、どのようなパスワードを有効とみなすかをプロパティで設定できます(表3)。例えば、パスワードに大文字英字を使わなくてもよいようにするのなら、RequireUppercaseプロパティにfalseを設定します。
| プロパティ名 | 説明 |
|---|---|
| RequiredLength | パスワードに必要な桁数を指定する |
| RequireNonLetterOrDigit | アルファベットでも数字でもない値が必要かどうかを指定する |
| RequireDigit | 数字が必要かどうかを指定する |
| RequireLowercase | 小文字英字が必要かどうかを指定する |
| RequireUppercase | 大文字英字が必要かどうかを指定する |
アカウントのロックアウト
ASP.NET Identity 2.0には、ログイン時に既定回数パスワードを間違えると、しばらくアカウントをロックしてログインできなくする、いわゆる「ロックアウト」機能が追加されました。ただし、テンプレートで生成されたコードにはこの機能は含まれていないため、自分で追加実装する必要があります。ロックアウトを実装するには、次の2つの手順が必要です。
- UserManagerオブジェクトへのプロパティ設定
- ログイン画面へのロックアウト処理の追加
実装方法を、順に見ていきましょう。
UserManagerオブジェクトへのプロパティ設定
ロックアウトを有効にするには、これまでにも出てきたApp_Start¥IdentityConfig.csファイル内のApplicationUserManager.Createメソッドに、ロックアウト機能を使用するためのプロパティ設定を追加します(リスト4)。
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
…(略)….
// アカウントロックアウト設定``
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
return manager;
}
}
設定しているプロパティについて、表4にまとめます。これらのプロパティを設定することで、アカウントロックアウト機能を使用する準備を行います。サンプルではロックアウト時間5分、ロックアウトされるまでの試行回数を5回に設定しています。
| プロパティ名 | 説明 |
|---|---|
| UserLockoutEnabledByDefault | 登録するユーザーが既定でロックアウトを有効にするかどうか指定する(AspNetUsersテーブルのLockoutEnabled列に設定される) |
| DefaultAccountLockoutTimeSpan | アカウントがロックアウトされる時間を指定する |
| MaxFailedAccessAttemptsBeforeLockout | アカウントがロックアウトされるまでの試行回数を指定する |
ログイン画面へのロックアウト処理の追加
次に、ロックアウト処理をログイン画面に組み込みます。そのためには、Account¥Login.aspx.csファイルのLogInメソッドを、テンプレートのコードから大幅に変更します(リスト5)。
protected void LogIn(object sender, EventArgs e)
{
if (IsValid)
{
// ユーザーのパスワードを検証します
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signedIn = false;
var user = manager.FindByName(Email.Text); //(1)
if (user != null)
{
if (manager.IsLockedOut(user.Id)) // (2)
{
// ユーザーがロックアウトされている
FailureText.Text = "ユーザーがロックアウトされています。しばらく待ってから再度ログインしてください。";
ErrorMessage.Visible = true;
return;
}
if (manager.CheckPassword(user, Password.Text)) // (3)
{
// パスワードが有効
signedIn = true;
}
else
{
// パスワードが無効
manager.AccessFailed(user.Id); //(4)
}
}
if (signedIn)
{
IdentityHelper.SignIn(manager, user, RememberMe.Checked);
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
}
else
{
FailureText.Text = "ユーザー名またはパスワードが無効です。";
ErrorMessage.Visible = true;
}
}
}
(1)ユーザー名でユーザーを取得する
ロックアウトされたユーザーかどうかを最初に確認するため、まずパスワードを使わずにユーザー情報を取得します。ユーザー情報が取得できなければ、そのままログオン失敗とします。
(2)ロックアウトされたユーザーかどうか確認する
UserManager<TUser>クラスのIsLockedOutメソッドを使い、ロックアウトされたユーザーかどうか確認します。ロックアウトされていればエラーメッセージを表示して、ログイン処理を中断します。
(3)パスワードをチェックする
UserManager<TUser>クラスのCheckPasswordメソッドを使い、入力したパスワードが有効かどうかチェックします。パスワードが有効なら、ログオン成功とします。
(4)ログオン失敗処理
パスワードが無効な場合、ロックアウトのためのログオン失敗回数を更新するため、UserManager<TUser>クラスのAccessFailedメソッドを呼び出します。
