我有一个场景,其中用户帐户被重置为未确认,并且其密码哈希和安全戳记被设置为null。每当我重新发送确认电子邮件时,我都会收到令牌无效的错误。这在创建新用户并发送确认电子邮件时非常适用。
System.Exception: Invalid token.
at PRISMdev.Controllers.AccountController.AddErrors(IdentityResult result)
at PRISMdev.Controllers.AccountController.<ConfirmEmail>d__d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Mvc.Async.TaskAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<BeginInvokeAsynchronousActionMethod>b__36(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<>c__DisplayClass2b.<BeginInvokeAction>b__1c()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
at System.Web.HttpApplication.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar)
ResendConfirmEmail
public async Task<ActionResult> ResendConfirmationEmail(string email)
{
ApplicationUser applicationUser = await UserManager.FindByEmailAsync(email);
if (applicationUser == null)
{
return Json(new { success = false });
}
else
{
var code = Url.Encode(await UserManager.GenerateEmailConfirmationTokenAsync(applicationUser.Id));
//var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = applicationUser.Id, code = code }, protocol: Request.Url.Scheme);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new {area = "", userId = applicationUser.Id, code = code }, protocol: Request.Url.Scheme);
//string callbackUrl = Request.Url.Scheme + System.Uri.SchemeDelimiter + Request.Url.Host + (Request.Url.IsDefaultPort ? "" : ":" + Request.Url.Port) + "/Account/ConfirmEmail?userId=" + Url.Encode(applicationUser.Id) + "&code=" + Url.Encode(code);
EmailHelper newEmail = new EmailHelper();
newEmail.To = applicationUser.Email;
newEmail.Subject = "PRISM-Assoc Confirm Account";
newEmail.BodyText = string.Format("Please click on this link to {0}: {1}", newEmail.Subject, callbackUrl);
newEmail.BodyHtml = "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>.";
newEmail.SendEmail();
return Json(new { success = true });
}
return View();
}
确认电子邮件
public async Task<ActionResult> ConfirmEmail(string userId, string code)
{
ViewBag.headerTitle = "Account Confirmed";
if (userId == null || code == null)
{
return View("Error");
}
IdentityResult result = await UserManager.ConfirmEmailAsync(userId, code);
if (result.Succeeded)
{
//send email for reseting password.
await SendResetPasswordEmail(userId);
return View("ConfirmEmail");
}
else
{
AddErrors(result);
return View();
}
}
Startup.Auth.cs
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.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
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}
身份模型
public class ApplicationUser : IdentityUser
{
// Setting GridColumn Annotations allows you to use AutoGenerateColumns on view to auto create the Grid based on the model. https://gridmvc.codeplex.com/
[Display(Name = "Name")]
[GridColumn(Title = "Name", SortEnabled = true, FilterEnabled = true, Width = "100")]
public string Name { get; set; }
[Display(Name = "Position")]
[GridColumn(Title = "Position", SortEnabled = true, FilterEnabled = true, Width = "50")]
public string Position { get; set; }
[NotMappedColumn]
public DateTime? RegisteredDate { get; set; }
[Display(Name = "Last Date Visited")]
[GridColumn(Title = "Last Visited", SortEnabled = true, FilterEnabled = true, Width = "40")]
public DateTime? LastVisitDate { get; set; }
[GridColumn(Title = "Org.", SortEnabled = true, Width = "100")]
public int? MemberOrgId { get; set; }
[NotMappedColumn]
public int? SponsorOrgId { get; set; }
[Display(Name = "Profile Picture")]
//[GridColumn(Title = "Profile Pic.", SortEnabled = true, FilterEnabled = true)]
[NotMappedColumn]
public string ProfilePictureSrc { get; set; }
[Display(Name = "Forum Username")]
//[GridColumn(Title = "Forum Username", SortEnabled = true, FilterEnabled = true, Width = "30")]
[NotMappedColumn]
public string ForumUsername { get; set; }
[Display(Name = "Receive System Emails")]
//[GridColumn(Title = "Rec. Sys Emails", SortEnabled = true, Width = "30")]
[NotMappedColumn]
public Boolean ReceiveSystemEmails { get; set; }
//////[ForeignKey("MemberOrgId")]
[NotMappedColumn]
public virtual MemberOrganizations Organization { get; set; }
//////[ForeignKey("SponsorOrgId")]
[NotMappedColumn]
public virtual SponsorOrganizations Sponsor { get; set; }
[Display(Name = "User Img")]
[UIHint("ProfPictureEdit")]
public virtual string ProfilePictureUrl
{
get
{
//TODO: update the folder when it isn't null to the blob location
if (string.IsNullOrEmpty(this.ProfilePictureSrc))
{
return "/Content/Images/userThumb.png";
}
else
{
BlobHelper helper = new BlobHelper();
string url = helper.getImageUrl(this.ProfilePictureSrc, "profilepicture");
return url;
}
}
}
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> 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;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
//public DbSet<Users> Users { get; set; }
public DbSet<MemberOrganizations> MemberOrganizations { get; set; }
public DbSet<ServiceCategories> ServiceCategories { get; set; }
public DbSet<SponsorOrganizations> SponsorOrganizations { get; set; }
public DbSet<SponsorServiceCategories> SponsorServiceCategories { get; set; }
public DbSet<MemberProjects> MemberProjects { get; set; }
public DbSet<MemberRFPs> MemberRFPs { get; set; }
public DbSet<OptionTypes> OptionTypes { get; set; }
public DbSet<Options> Options { get; set; }
public DbSet<MemberOrganizationsFundTypes> MemberOrganizationsFundTypes { get; set; }
public DbSet<MemberOrganizationsPlanTypes> MemberOrganizationsPlanTypes { get; set; }
public DbSet<MemberOrganizationsOperatingSystems> MemberOrganizationsOperatingSystems { get; set; }
public DbSet<MemberOrganizationsDatabases> MemberOrganizationsDatabases { get; set; }
public DbSet<BoardAndDirectors> BoardAndDirectors { get; set; }
public DbSet<Pages> Pages { get; set; }
public DbSet<SiteFiles> SiteFiles { get; set; }
public DbSet<Surveys> Surveys { get; set; }
public DbSet<BoardEvents> BoardEvents { get; set; }
public DbSet<PRISMEvent> PRISMEvents { get; set; }
public DbSet<PRISMEventGuestAttendees> PRISMEventGuestAttendees { get; set; }
public DbSet<PRISMEventMemberAttendees> PRISMEventMemberAttendees { get; set; }
public DbSet<PRISMEventSponsorAttendees> PRISMEventSponsorAttendees { get; set; }
public DbSet<CustomEmailsAndMessages> CustomEmailsAndMessages { get; set; }
public DbSet<NonSiteMemberProfile> NonSiteMemberProfile { get; set; }
public DbSet<MemberDues> MemberDues { get; set; }
public DbSet<MemberDuesReceived> MemberDuesReceived { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
identityconfig.cs
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>()));
// 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 = 8,
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>
{
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;
}
}