自定义ASP.NET Identity(二)- 修改ASP.NET Identity的用户主键
在Visual Studio 2013中,默认Web应用使用字符串作为用户账号的主键类型。ASP.NET Identity允许你根据你的数据需要改变这个主键的类型。泪如,你可以将主键类型有字符创类型修改为整数类型。
本章的主题将向你展示怎样开始默认的Web应用程序并且修改用户账户主键到整数类型。你可以使用相同的修改方法在你的工程中实现任意类型的用户账户主键。展示了在默认Web应用中怎样完成这些修改,你可以应用类似的修改方法定制应用。还将展示MVC或者Web Forms中所应该做的修改。
在本教程中学习的步骤,你必须使用Visual Studio 2013 Update2(或者更高版本),从ASP.NET Web 应用模板创建一个Web应用。Update3中的模板改变了,本主题将展示怎样在Update2和Update3中修改模板。
本章包含以下章节:
- 修改身份用户类主键类型
- 修改自定义身份类的主键类型
- 修改上下文类和用户管理器的主键类型
- 修改主键类型的启动配置
- MVC with Update 2, 修改AccountController的主键类型
- MVC with Update 3, 修改AccountController和ManageController的主键类型
- Web Forms Update 2, 修改Account页面的主键类型
- Web Forms Update 3, 修改Account页面的主键类型
- 运行应用
修改身份用户类主键类型
应用ASP.NET应用模板创建工程,指定ApplicationUser类的用户账号主键为整数类型。在IndentityModels.cs文件中,修改ApplicationUser类的继承接口IdentityUser的泛型参数TKey的类型为int类型。一也可以修改其它三个尚未实现的自定义类的名称。
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim> { ...
你已经修改了主键类型,但是应用的其余部分这个主键仍然是字符串类型。你必须在代码中明确声明主键的类型。
在ApplicationUser类中,修改GenerateUserIdentityAsync方法使其包含int类型,如下高亮显示的代码。这个修改在Update 3的Web Forms工程中不是必要的。
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; }
修改自定义身份类的主键类型
其它的Identity类,如:IdentityUserRole, IdentityUserClaim, IdentityUserLogin, IdentityRole, UserStore, RoleStore, 仍然使用字符串作为主键。使用整数类型作为主键创建这些类的新的版本。你不需要在这些类中实现太多的代码,你只需要设置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文件,使用新的带有int类型主键的用户存储类修改ApplicationUserManger类
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文件中,替换OnValidateIndentity的代码,如下面高亮所示。注意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的基础类做了很多的修改。如果试着编译工程,你将被提示很多的错误。幸运的是,出现的错误都是相似的。Identity类期待一个整型主键值,但是控制器(或者Web Form)传递了一个字符串值。每一种情况下你都需要将字符串转换为整型来调用GetUserId<int>方法。你可以根据编译错误列表或者按照下面的进行修改来处理错误。
剩下的修改取决于工程类型,你正在创建和在Visual Studio中安装的更新版本。你可以通过下面的连接直接找到相关的处理方法。
- MVC Update 2, 修改AccountController主键类型
- MVC Update 3, 修改AccountController 和ManageController 主键类型
- Web Forms Update 2, 修改Account页面主键类型
- Web Forms Update 3, 修改Account页面主键类型
MVC Update 2, 修改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; }
你现在可以运行应用并且注册一个新用户
MVC Update 3, 修改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 }); }
打开ManagerController.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; }
你现在可以运行应用并且注册一个新用户
Web Forms Update 2, 修改Account页面主键类型
对于Web Forms Update2,你需要修改下面的页面。
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(); 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); }
你现在可以运行应用并且注册一个新用户
Web Forms Update 3, 修改Account页面主键类型
对于Web Forms Update3,你需要修改下面的页面。
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。