ASP.NET Identity でユーザーの主キーを変更する
作成者: Tom FitzMacken
Visual Studio 2013 では、既定の Web アプリケーションでは、ユーザー アカウントのキーに文字列値が使用されます。 ASP.NET Identity を使用すると、データ要件を満たすようにキーの型を変更できます。 たとえば、キーの型を文字列から整数に変更できます。
このトピックでは、既定の Web アプリケーションから開始し、ユーザー アカウント キーを整数に変更する方法について説明します。 同じ変更を使用して、プロジェクトに任意の型のキーを実装できます。 既定の Web アプリケーションでこれらの変更を行う方法を示しますが、カスタマイズしたアプリケーションにも同様の変更を適用できます。 MVC または Web フォームを操作するときに必要な変更を示します。
チュートリアルで使用するソフトウェアのバージョン
- Update 2 が適用された Visual Studio 2013 (またはそれ以降)
- ASP.NET Identity 2.1 以降
このチュートリアルの手順を実行するには、Visual Studio 2013 Update 2 (またはそれ以降) と、ASP.NET Web アプリケーション テンプレートから作成された Web アプリケーションが必要です。 テンプレートは Update 3 で変更されました。 このトピックでは、Update 2 および Update 3 でテンプレートを変更する方法について説明します。
このトピックは、次のセクションで構成されています。
- ID ユーザー クラスのキーの型を変更する
- キー型を使用するカスタマイズされた ID クラスを追加する
- キー型を使用するようにコンテキスト クラスとユーザー マネージャーを変更する
- キー型を使用するようにスタートアップ構成を変更する
- Update 2が適用された MVC の場合は、AccountController を変更してキー型を渡します
- Update 3 が適用された MVC の場合は、AccountController と ManageController を変更してキー型を渡します
- Update 2 が適用された Web フォームの場合は、キー型を渡す [アカウント] ページを変更します
- Update 3 が適用された Web フォームの場合は、キー型を渡す [アカウント] ページを変更します
- アプリケーションを実行する
- その他のリソース
ID ユーザー クラスのキーの型を変更する
ASP.NET Web アプリケーション テンプレートから作成したプロジェクトで、ApplicationUser クラスがユーザー アカウントのキーに整数を使用することを指定します。 IdentityModels.cs で、TKey ジェネリック パラメーターの int 型を持つ IdentityUser から継承するように ApplicationUser クラスを変更します。 また、まだ実装していない 3 つのカスタマイズされたクラスの名前も渡します。
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole,
CustomUserClaim>
{
...
キーの型を変更しましたが、既定では、アプリケーションの残りの部分ではキーが文字列であると見なされます。 文字列を前提とするコード内のキーの型を明示的に指定する必要があります。
ApplicationUser クラスで、次の強調表示されたコードに示すように、GenerateUserIdentityAsync メソッドを int を含むように変更します。 この変更は、Update 3 が適用された Web フォーム プロジェクト テンプレートでは必要ありません。
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
UserManager<ApplicationUser, int> manager)
{
// Note the authenticationType must match the one defined in
// CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(
this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
キー型を使用するカスタマイズされた ID クラスを追加する
IdentityUserRole、IdentityUserClaim、IdentityUserLogin、IdentityRole、UserStore、RoleStore などの他の ID クラスは、文字列キーを使用するように設定されています。 キーの整数を指定するこれらのクラスの新しいバージョンを作成します。 これらのクラスに多くの実装コードを提供する必要はありません。主に int をキーとして設定するだけです。
IdentityModels.cs ファイルに次のクラスを追加します。
public class CustomUserRole : IdentityUserRole<int> { }
public class CustomUserClaim : IdentityUserClaim<int> { }
public class CustomUserLogin : IdentityUserLogin<int> { }
public class CustomRole : IdentityRole<int, CustomUserRole>
{
public CustomRole() { }
public CustomRole(string name) { Name = name; }
}
public class CustomUserStore : UserStore<ApplicationUser, CustomRole, int,
CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public CustomUserStore(ApplicationDbContext context)
: base(context)
{
}
}
public class CustomRoleStore : RoleStore<CustomRole, int, CustomUserRole>
{
public CustomRoleStore(ApplicationDbContext context)
: base(context)
{
}
}
キー型を使用するようにコンテキスト クラスとユーザー マネージャーを変更する
IdentityModels.cs で、強調表示されたコードに示すように、新しいカスタマイズされたクラスとキーの int を使用するように ApplicationDbContext クラスの定義を変更します。
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole,
int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
...
ThrowIfV1Schema パラメーターは、コンストラクターで無効になっています。 ThrowIfV1Schema 値が渡されないようにコンストラクターを変更します。
public ApplicationDbContext()
: base("DefaultConnection")
{
}
IdentityConfig.cs開き、ApplicationUserManger クラスを変更して、新しいユーザー ストア クラスを使用してデータを保持し、キーの int を使用します。
public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
: base(store)
{
}
public static ApplicationUserManager Create(
IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(
new CustomUserStore(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser, int>(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 in here.
manager.RegisterTwoFactorProvider("PhoneCode",
new PhoneNumberTokenProvider<ApplicationUser, int>
{
MessageFormat = "Your security code is: {0}"
});
manager.RegisterTwoFactorProvider("EmailCode",
new EmailTokenProvider<ApplicationUser, int>
{
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, int>(
dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
Update 3 テンプレートでは、ApplicationSignInManager クラスを変更する必要があります。
public class ApplicationSignInManager : SignInManager<ApplicationUser, int>
{ ... }
キー型を使用するようにスタートアップ構成を変更する
Startup.Auth.cs で、次に強調表示されているように OnValidateIdentity コードを置き換えます。 getUserIdCallback 定義では、文字列値を整数に解析することに注意してください。
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator
.OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) =>
user.GenerateUserIdentityAsync(manager),
getUserIdCallback:(id)=>(id.GetUserId<int>()))
}
});
プロジェクトで GetUserId メソッドの一般的な実装が認識されない場合は、ASP.NET Identity NuGet パッケージをバージョン 2.1 に更新する必要がある場合があります
ASP.NET Identity で使用されるインフラストラクチャ クラスに多くの変更を加えています。 プロジェクトをコンパイルしようとすると、多くのエラーが発生します。 幸いなことに、残りのエラーはすべて似ています。 ID クラスはキーの整数を受け取りますが、コントローラー (または Web フォーム) は文字列値を渡しています。 いずれの場合も、GetUserId<int> を呼び出して文字列から整数に変換する必要があります。 コンパイルからエラー一覧を操作するか、次の変更に従うことができます。
残りの変更は、作成するプロジェクトの種類と、Visual Studio にインストールした更新プログラムによって異なります。 関連するセクションには、次のリンクから直接移動できます
- Update 2が適用された MVC の場合は、AccountController を変更してキー型を渡します
- Update 3 が適用された MVC の場合は、AccountController と ManageController を変更してキー型を渡します
- Update 2 が適用された Web フォームの場合は、キー型を渡す [アカウント] ページを変更します
- Update 3 が適用された Web フォームの場合は、キー型を渡す [アカウント] ページを変更します
Update 2が適用された MVC の場合は、AccountController を変更してキー型を渡します
AccountController.cs ファイルを開きます。 次のメソッドを変更する必要があります。
ConfirmEmail メソッド
public async Task<ActionResult> ConfirmEmail(int userId, string code)
{
if (userId == default(int) || code == null)
{
return View("Error");
}
IdentityResult result = await UserManager.ConfirmEmailAsync(userId, code);
if (result.Succeeded)
{
return View("ConfirmEmail");
}
else
{
AddErrors(result);
return View();
}
}
Disassociate メソッド
public async Task<ActionResult> Disassociate(string loginProvider, string providerKey)
{
ManageMessageId? message = null;
IdentityResult result = await UserManager.RemoveLoginAsync(
User.Identity.GetUserId<int>(),
new UserLoginInfo(loginProvider, providerKey));
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
await SignInAsync(user, isPersistent: false);
message = ManageMessageId.RemoveLoginSuccess;
}
else
{
message = ManageMessageId.Error;
}
return RedirectToAction("Manage", new { Message = message });
}
Manage(ManageUserViewModel) メソッド
public async Task<ActionResult> Manage(ManageUserViewModel model)
{
bool hasPassword = HasPassword();
ViewBag.HasLocalPassword = hasPassword;
ViewBag.ReturnUrl = Url.Action("Manage");
if (hasPassword)
{
if (ModelState.IsValid)
{
IdentityResult result = await UserManager.ChangePasswordAsync(
User.Identity.GetUserId<int>(),
model.OldPassword,
model.NewPassword);
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(
User.Identity.GetUserId<int>());
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Manage", new {
Message = ManageMessageId.ChangePasswordSuccess });
}
else
{
AddErrors(result);
}
}
}
else
{
// User does not have a password so remove any validation errors caused
// by a missing OldPassword field
ModelState state = ModelState["OldPassword"];
if (state != null)
{
state.Errors.Clear();
}
if (ModelState.IsValid)
{
IdentityResult result = await UserManager.AddPasswordAsync(
User.Identity.GetUserId<int>(), model.NewPassword);
if (result.Succeeded)
{
return RedirectToAction("Manage", new {
Message = ManageMessageId.SetPasswordSuccess });
}
else
{
AddErrors(result);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
LinkLoginCallback メソッド
public async Task<ActionResult> LinkLoginCallback()
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey,
User.Identity.GetUserId());
if (loginInfo == null)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
}
IdentityResult result = await UserManager.AddLoginAsync(
User.Identity.GetUserId<int>(), loginInfo.Login);
if (result.Succeeded)
{
return RedirectToAction("Manage");
}
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
}
RemoveAccountList メソッド
public ActionResult RemoveAccountList()
{
var linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId<int>());
ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;
return (ActionResult)PartialView("_RemoveAccountPartial", linkedAccounts);
}
HasPassword メソッド
private bool HasPassword()
{
var user = UserManager.FindById(User.Identity.GetUserId<int>());
if (user != null)
{
return user.PasswordHash != null;
}
return false;
}
これで、アプリケーションを実行し、新しいユーザーを登録できるようになりました。
Update 3 が適用された MVC の場合は、AccountController と ManageController を変更してキー型を渡します
AccountController.cs ファイルを開きます。 次のメソッドを変更する必要があります。
ConfirmEmail メソッド
public async Task<ActionResult> ConfirmEmail(int userId, string code)
{
if (userId == default(int) || code == null)
{
return View("Error");
}
IdentityResult result = await UserManager.ConfirmEmailAsync(userId, code);
return View(result.Succeeded ? "ConfirmEmail" : "Error");
}
SendCode メソッド
public async Task<ActionResult> SendCode(string returnUrl, bool rememberMe)
{
var userId = await SignInManager.GetVerifiedUserIdAsync();
if (userId == default(int))
{
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, RememberMe = rememberMe });
}
ManageController.cs ファイルを開きます。 次のメソッドを変更する必要があります。
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 authentication provider has been set."
: message == ManageMessageId.Error ? "An error has occurred."
: message == ManageMessageId.AddPhoneSuccess ? "Your 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<int>()),
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(User.Identity.GetUserId<int>()),
Logins = await UserManager.GetLoginsAsync(User.Identity.GetUserId<int>()),
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(
User.Identity.GetUserId())
};
return View(model);
}
RemoveLogin メソッド
public ActionResult RemoveLogin()
{
var linkedAccounts = UserManager.GetLogins((User.Identity.GetUserId<int>()));
ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;
return View(linkedAccounts);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> RemoveLogin(string loginProvider, string providerKey)
{
ManageMessageId? message;
var result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId<int>(),
new UserLoginInfo(loginProvider, providerKey));
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
message = ManageMessageId.RemoveLoginSuccess;
}
else
{
message = ManageMessageId.Error;
}
return RedirectToAction("ManageLogins", new { Message = message });
}
AddPhoneNumber メソッド
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<int>(), 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 });
}
EnableTwoFactorAuthentication メソッド
public async Task<ActionResult> EnableTwoFactorAuthentication()
{
await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId<int>(), true);
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
return RedirectToAction("Index", "Manage");
}
DisableTwoFactorAuthentication メソッド
public async Task<ActionResult> DisableTwoFactorAuthentication()
{
await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId<int>(), false);
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
return RedirectToAction("Index", "Manage");
}
VerifyPhoneNumber メソッド
public async Task<ActionResult> VerifyPhoneNumber(string phoneNumber)
{
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(
User.Identity.GetUserId<int>(), phoneNumber);
// Send an SMS through the SMS provider to verify the phone number
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await UserManager.ChangePhoneNumberAsync(
User.Identity.GetUserId<int>(), model.PhoneNumber, model.Code);
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
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);
}
RemovePhoneNumber メソッド
public async Task<ActionResult> RemovePhoneNumber()
{
var result = await UserManager.SetPhoneNumberAsync(User.Identity.GetUserId<int>(), null);
if (!result.Succeeded)
{
return RedirectToAction("Index", new { Message = ManageMessageId.Error });
}
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
return RedirectToAction("Index", new { Message = ManageMessageId.RemovePhoneSuccess });
}
ChangePassword メソッド
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ChangePassword(ChangePasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await UserManager.ChangePasswordAsync(
User.Identity.GetUserId<int>(), model.OldPassword, model.NewPassword);
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess });
}
AddErrors(result);
return View(model);
}
SetPassword メソッド
public async Task<ActionResult> SetPassword(SetPasswordViewModel model)
{
if (ModelState.IsValid)
{
var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId<int>(), model.NewPassword);
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
return RedirectToAction("Index", new { Message = ManageMessageId.SetPasswordSuccess });
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
ManageLogins メソッド
public async Task<ActionResult> ManageLogins(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
: message == ManageMessageId.Error ? "An error has occurred."
: "";
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
if (user == null)
{
return View("Error");
}
var userLogins = await UserManager.GetLoginsAsync(User.Identity.GetUserId<int>());
var otherLogins = AuthenticationManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList();
ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1;
return View(new ManageLoginsViewModel
{
CurrentLogins = userLogins,
OtherLogins = otherLogins
});
}
LinkLoginCallback メソッド
public async Task<ActionResult> LinkLoginCallback()
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
if (loginInfo == null)
{
return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
}
var result = await UserManager.AddLoginAsync(User.Identity.GetUserId<int>(),
loginInfo.Login);
return result.Succeeded ? RedirectToAction("ManageLogins") :
RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
}
HasPassword メソッド
private bool HasPassword()
{
var user = UserManager.FindById(User.Identity.GetUserId<int>());
if (user != null)
{
return user.PasswordHash != null;
}
return false;
}
HasPhoneNumber メソッド
private bool HasPhoneNumber()
{
var user = UserManager.FindById(User.Identity.GetUserId<int>());
if (user != null)
{
return user.PhoneNumber != null;
}
return false;
}
これで、アプリケーションを実行し、新しいユーザーを登録できるようになりました。
Update 2 が適用された Web フォームの場合は、キー型を渡す [アカウント] ページを変更します
Update 2 が適用された Web フォームの場合は、次のページを変更する必要があります。
Confirm.aspx.cx
protected void Page_Load(object sender, EventArgs e)
{
string code = IdentityHelper.GetCodeFromRequest(Request);
string userId = IdentityHelper.GetUserIdFromRequest(Request);
if (code != null && userId != null)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var result = manager.ConfirmEmail(Int32.Parse(userId), code);
if (result.Succeeded)
{
StatusMessage = "Thank you for confirming your account.";
return;
}
}
StatusMessage = "An error has occurred";
}
RegisterExternalLogin.aspx.cs
protected void Page_Load()
{
// Process the result from an auth provider in the request
ProviderName = IdentityHelper.GetProviderNameFromRequest(Request);
if (String.IsNullOrEmpty(ProviderName))
{
RedirectOnFail();
return;
}
if (!IsPostBack)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var loginInfo = Context.GetOwinContext().Authentication.GetExternalLoginInfo();
if (loginInfo == null)
{
RedirectOnFail();
return;
}
var user = manager.Find(loginInfo.Login);
if (user != null)
{
IdentityHelper.SignIn(manager, user, isPersistent: false);
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
}
else if (User.Identity.IsAuthenticated)
{
// Apply Xsrf check when linking
var verifiedloginInfo = Context.GetOwinContext().Authentication
.GetExternalLoginInfo(IdentityHelper.XsrfKey, User.Identity.GetUserId());
if (verifiedloginInfo == null)
{
RedirectOnFail();
return;
}
var result = manager.AddLogin(User.Identity.GetUserId<int>(),
verifiedloginInfo.Login);
if (result.Succeeded)
{
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"],
Response);
}
else
{
AddErrors(result);
return;
}
}
else
{
email.Text = loginInfo.Email;
}
}
}
Manage.aspx.cs
private bool HasPassword(ApplicationUserManager manager)
{
return manager.HasPassword(User.Identity.GetUserId<int>());
}
protected void Page_Load()
{
if (!IsPostBack)
{
// Determine the sections to render
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
if (HasPassword(manager))
{
changePasswordHolder.Visible = true;
}
else
{
setPassword.Visible = true;
changePasswordHolder.Visible = false;
}
CanRemoveExternalLogins = manager.GetLogins(
User.Identity.GetUserId<int>()).Count() > 1;
// Render success message
var message = Request.QueryString["m"];
if (message != null)
{
// Strip the query string from action
Form.Action = ResolveUrl("~/Account/Manage");
SuccessMessage =
message == "ChangePwdSuccess" ? "Your password has been changed."
: message == "SetPwdSuccess" ? "Your password has been set."
: message == "RemoveLoginSuccess" ? "The account was removed."
: String.Empty;
successMessage.Visible = !String.IsNullOrEmpty(SuccessMessage);
}
}
}
protected void ChangePassword_Click(object sender, EventArgs e)
{
if (IsValid)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
IdentityResult result = manager.ChangePassword(
User.Identity.GetUserId<int>(),
CurrentPassword.Text,
NewPassword.Text);
if (result.Succeeded)
{
var user = manager.FindById(User.Identity.GetUserId<int>());
IdentityHelper.SignIn(manager, user, isPersistent: false);
Response.Redirect("~/Account/Manage?m=ChangePwdSuccess");
}
else
{
AddErrors(result);
}
}
}
protected void SetPassword_Click(object sender, EventArgs e)
{
if (IsValid)
{
// Create the local login info and link the local account to the user
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
IdentityResult result = manager.AddPassword(User.Identity.GetUserId<int>(),
password.Text);
if (result.Succeeded)
{
Response.Redirect("~/Account/Manage?m=SetPwdSuccess");
}
else
{
AddErrors(result);
}
}
}
public IEnumerable<UserLoginInfo> GetLogins()
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var accounts = manager.GetLogins(User.Identity.GetUserId<int>());
CanRemoveExternalLogins = accounts.Count() > 1 || HasPassword(manager);
return accounts;
}
public void RemoveLogin(string loginProvider, string providerKey)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var result = manager.RemoveLogin(User.Identity.GetUserId<int>(),
new UserLoginInfo(loginProvider, providerKey));
string msg = String.Empty;
if (result.Succeeded)
{
var user = manager.FindById(User.Identity.GetUserId<int>());
IdentityHelper.SignIn(manager, user, isPersistent: false);
msg = "?m=RemoveLoginSuccess";
}
Response.Redirect("~/Account/Manage" + msg);
}
これで、アプリケーションを実行し、新しいユーザーを登録できるようになりました。
Update 3 が適用された Web フォームの場合は、キー型を渡す [アカウント] ページを変更します
Update 3 が適用された Web フォームの場合は、次のページを変更する必要があります。
Confirm.aspx.cx
protected void Page_Load(object sender, EventArgs e)
{
string code = IdentityHelper.GetCodeFromRequest(Request);
string userId = IdentityHelper.GetUserIdFromRequest(Request);
if (code != null && userId != null)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var result = manager.ConfirmEmail(Int32.Parse(userId), code);
if (result.Succeeded)
{
StatusMessage = "Thank you for confirming your account.";
return;
}
}
StatusMessage = "An error has occurred";
}
RegisterExternalLogin.aspx.cs
protected void Page_Load()
{
// Process the result from an auth provider in the request
ProviderName = IdentityHelper.GetProviderNameFromRequest(Request);
if (String.IsNullOrEmpty(ProviderName))
{
RedirectOnFail();
return;
}
if (!IsPostBack)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var loginInfo = Context.GetOwinContext().Authentication.GetExternalLoginInfo();
if (loginInfo == null)
{
RedirectOnFail();
return;
}
var user = manager.Find(loginInfo.Login);
if (user != null)
{
IdentityHelper.SignIn(manager, user, isPersistent: false);
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
}
else if (User.Identity.IsAuthenticated)
{
// Apply Xsrf check when linking
var verifiedloginInfo = Context.GetOwinContext().Authentication
.GetExternalLoginInfo(IdentityHelper.XsrfKey, User.Identity.GetUserId());
if (verifiedloginInfo == null)
{
RedirectOnFail();
return;
}
var result = manager.AddLogin(User.Identity.GetUserId<int>(),
verifiedloginInfo.Login);
if (result.Succeeded)
{
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"],
Response);
}
else
{
AddErrors(result);
return;
}
}
else
{
email.Text = loginInfo.Email;
}
}
}
Manage.aspx.cs
public partial class Manage : System.Web.UI.Page
{
protected string SuccessMessage
{
get;
private set;
}
private bool HasPassword(ApplicationUserManager manager)
{
return manager.HasPassword(User.Identity.GetUserId<int>());
}
public bool HasPhoneNumber { get; private set; }
public bool TwoFactorEnabled { get; private set; }
public bool TwoFactorBrowserRemembered { get; private set; }
public int LoginsCount { get; set; }
protected void Page_Load()
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
HasPhoneNumber = String.IsNullOrEmpty(manager.GetPhoneNumber(
User.Identity.GetUserId<int>()));
// Enable this after setting up two-factor authentientication
//PhoneNumber.Text = manager.GetPhoneNumber(User.Identity.GetUserId()) ?? String.Empty;
TwoFactorEnabled = manager.GetTwoFactorEnabled(User.Identity.GetUserId<int>());
LoginsCount = manager.GetLogins(User.Identity.GetUserId<int>()).Count;
var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
if (!IsPostBack)
{
// Determine the sections to render
if (HasPassword(manager))
{
ChangePassword.Visible = true;
}
else
{
CreatePassword.Visible = true;
ChangePassword.Visible = false;
}
// Render success message
var message = Request.QueryString["m"];
if (message != null)
{
// Strip the query string from action
Form.Action = ResolveUrl("~/Account/Manage");
SuccessMessage =
message == "ChangePwdSuccess" ? "Your password has been changed."
: message == "SetPwdSuccess" ? "Your password has been set."
: message == "RemoveLoginSuccess" ? "The account was removed."
: message == "AddPhoneNumberSuccess" ? "Phone number has been added"
: message == "RemovePhoneNumberSuccess" ? "Phone number was removed"
: String.Empty;
successMessage.Visible = !String.IsNullOrEmpty(SuccessMessage);
}
}
}
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
// Remove phonenumber from user
protected void RemovePhone_Click(object sender, EventArgs e)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var result = manager.SetPhoneNumber(User.Identity.GetUserId<int>(), null);
if (!result.Succeeded)
{
return;
}
var user = manager.FindById(User.Identity.GetUserId<int>());
if (user != null)
{
IdentityHelper.SignIn(manager, user, isPersistent: false);
Response.Redirect("/Account/Manage?m=RemovePhoneNumberSuccess");
}
}
// DisableTwoFactorAuthentication
protected void TwoFactorDisable_Click(object sender, EventArgs e)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
manager.SetTwoFactorEnabled(User.Identity.GetUserId<int>(), false);
Response.Redirect("/Account/Manage");
}
//EnableTwoFactorAuthentication
protected void TwoFactorEnable_Click(object sender, EventArgs e)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
manager.SetTwoFactorEnabled(User.Identity.GetUserId<int>(), true);
Response.Redirect("/Account/Manage");
}
}
VerifyPhoneNumber.aspx.cs
public partial class VerifyPhoneNumber : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var phonenumber = Request.QueryString["PhoneNumber"];
var code = manager.GenerateChangePhoneNumberToken(
User.Identity.GetUserId<int>(), phonenumber);
PhoneNumber.Value = phonenumber;
}
protected void Code_Click(object sender, EventArgs e)
{
if (!ModelState.IsValid)
{
ModelState.AddModelError("", "Invalid code");
return;
}
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var result = manager.ChangePhoneNumber(
User.Identity.GetUserId<int>(), PhoneNumber.Value, Code.Text);
if (result.Succeeded)
{
var user = manager.FindById(User.Identity.GetUserId<int>());
if (user != null)
{
IdentityHelper.SignIn(manager, user, false);
Response.Redirect("/Account/Manage?m=AddPhoneNumberSuccess");
}
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "Failed to verify phone");
}
}
AddPhoneNumber.aspx.cs
public partial class AddPhoneNumber : System.Web.UI.Page
{
protected void PhoneNumber_Click(object sender, EventArgs e)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var code = manager.GenerateChangePhoneNumberToken(
User.Identity.GetUserId<int>(), PhoneNumber.Text);
if (manager.SmsService != null)
{
var message = new IdentityMessage
{
Destination = PhoneNumber.Text,
Body = "Your security code is " + code
};
manager.SmsService.Send(message);
}
Response.Redirect("/Account/VerifyPhoneNumber?PhoneNumber=" + HttpUtility.UrlEncode(PhoneNumber.Text));
}
}
ManagePassword.aspx.cs
public partial class ManagePassword : System.Web.UI.Page
{
protected string SuccessMessage
{
get;
private set;
}
private bool HasPassword(ApplicationUserManager manager)
{
return manager.HasPassword(User.Identity.GetUserId<int>());
}
protected void Page_Load(object sender, EventArgs e)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
if (!IsPostBack)
{
// Determine the sections to render
if (HasPassword(manager))
{
changePasswordHolder.Visible = true;
}
else
{
setPassword.Visible = true;
changePasswordHolder.Visible = false;
}
// Render success message
var message = Request.QueryString["m"];
if (message != null)
{
// Strip the query string from action
Form.Action = ResolveUrl("~/Account/Manage");
}
}
}
protected void ChangePassword_Click(object sender, EventArgs e)
{
if (IsValid)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
IdentityResult result = manager.ChangePassword(
User.Identity.GetUserId<int>(), CurrentPassword.Text, NewPassword.Text);
if (result.Succeeded)
{
var user = manager.FindById(User.Identity.GetUserId<int>());
IdentityHelper.SignIn(manager, user, isPersistent: false);
Response.Redirect("~/Account/Manage?m=ChangePwdSuccess");
}
else
{
AddErrors(result);
}
}
}
protected void SetPassword_Click(object sender, EventArgs e)
{
if (IsValid)
{
// Create the local login info and link the local account to the user
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
IdentityResult result = manager.AddPassword(
User.Identity.GetUserId<int>(), password.Text);
if (result.Succeeded)
{
Response.Redirect("~/Account/Manage?m=SetPwdSuccess");
}
else
{
AddErrors(result);
}
}
}
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
}
ManageLogins.aspx.cs
public partial class ManageLogins : System.Web.UI.Page
{
protected string SuccessMessage
{
get;
private set;
}
protected bool CanRemoveExternalLogins
{
get;
private set;
}
private bool HasPassword(ApplicationUserManager manager)
{
return manager.HasPassword(User.Identity.GetUserId<int>());
}
protected void Page_Load(object sender, EventArgs e)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
CanRemoveExternalLogins = manager.GetLogins(
User.Identity.GetUserId<int>()).Count() > 1;
SuccessMessage = String.Empty;
successMessage.Visible = !String.IsNullOrEmpty(SuccessMessage);
}
public IEnumerable<UserLoginInfo> GetLogins()
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var accounts = manager.GetLogins(User.Identity.GetUserId<int>());
CanRemoveExternalLogins = accounts.Count() > 1 || HasPassword(manager);
return accounts;
}
public void RemoveLogin(string loginProvider, string providerKey)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var result = manager.RemoveLogin(
User.Identity.GetUserId<int>(), new UserLoginInfo(loginProvider, providerKey));
string msg = String.Empty;
if (result.Succeeded)
{
var user = manager.FindById(User.Identity.GetUserId<int>());
IdentityHelper.SignIn(manager, user, isPersistent: false);
msg = "?m=RemoveLoginSuccess";
}
Response.Redirect("~/Account/ManageLogins" + msg);
}
}
TwoFactorAuthenticationSignIn.aspx.cs
public partial class TwoFactorAuthenticationSignIn : System.Web.UI.Page
{
private ApplicationSignInManager signinManager;
private ApplicationUserManager manager;
public TwoFactorAuthenticationSignIn()
{
manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
signinManager = Context.GetOwinContext().GetUserManager<ApplicationSignInManager>();
}
protected void Page_Load(object sender, EventArgs e)
{
var userId = signinManager.GetVerifiedUserId<ApplicationUser, int>();
if (userId == default(int))
{
Response.Redirect("/Account/Error", true);
}
var userFactors = manager.GetValidTwoFactorProviders(userId);
Providers.DataSource = userFactors.Select(x => x).ToList();
Providers.DataBind();
}
protected void CodeSubmit_Click(object sender, EventArgs e)
{
bool rememberMe = false;
bool.TryParse(Request.QueryString["RememberMe"], out rememberMe);
var result = signinManager.TwoFactorSignIn<ApplicationUser, int>(SelectedProvider.Value, Code.Text, isPersistent: rememberMe, rememberBrowser: RememberBrowser.Checked);
switch (result)
{
case SignInStatus.Success:
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
break;
case SignInStatus.LockedOut:
Response.Redirect("/Account/Lockout");
break;
case SignInStatus.Failure:
default:
FailureText.Text = "Invalid code";
ErrorMessage.Visible = true;
break;
}
}
protected void ProviderSubmit_Click(object sender, EventArgs e)
{
if (!signinManager.SendTwoFactorCode(Providers.SelectedValue))
{
Response.Redirect("/Account/Error");
}
var user = manager.FindById(signinManager.GetVerifiedUserId<ApplicationUser, int>());
if (user != null)
{
var code = manager.GenerateTwoFactorToken(user.Id, Providers.SelectedValue);
}
SelectedProvider.Value = Providers.SelectedValue;
sendcode.Visible = false;
verifycode.Visible = true;
}
}
アプリケーションの実行
既定の Web アプリケーション テンプレートに必要なすべての変更が完了しました。 アプリケーションを実行し、新しいユーザーを登録します。 ユーザーを登録すると、AspNetUsers テーブルに整数の ID 列があることがわかります。
別の主キーを使用して ASP.NET Identity テーブルを以前に作成した場合は、追加の変更を加える必要があります。 可能であれば、既存のデータベースを削除するだけです。 Web アプリケーションを実行して新しいユーザーを追加すると、正しいデザインでデータベースが再作成されます。 削除できない場合は、最初にコードの移行を実行してテーブルを変更します。 ただし、新しい整数主キーは、データベースの SQL IDENTITY プロパティとして設定されません。 ID 列を IDENTITY として手動で設定する必要があります。