1. ホーム
  2. c#

Asp.NET Identity 2で「Invalid Token」エラーが発生する。

2023-07-29 20:06:24

質問

私は Asp.Net-Identity-2 を使用しており、以下の方法を使用して電子メール検証コードを確認しようとしています。しかし、私は 無効なトークンです。 というエラーメッセージが表示されます。

  • My ApplicationのUser Managerはこのようになっています。

    public class AppUserManager : UserManager<AppUser>
    {
        public AppUserManager(IUserStore<AppUser> store) : base(store) { }
    
        public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
        {
            AppIdentityDbContext db = context.Get<AppIdentityDbContext>();
            AppUserManager manager = new AppUserManager(new UserStore<AppUser>(db));
    
            manager.PasswordValidator = new PasswordValidator { 
                RequiredLength = 6,
                RequireNonLetterOrDigit = false,
                RequireDigit = false,
                RequireLowercase = true,
                RequireUppercase = true
            };
    
            manager.UserValidator = new UserValidator<AppUser>(manager)
            {
                AllowOnlyAlphanumericUserNames = true,
                RequireUniqueEmail = true
            };
    
            var dataProtectionProvider = options.DataProtectionProvider;
    
            //token life span is 3 hours
            if (dataProtectionProvider != null)
            {
                manager.UserTokenProvider =
                   new DataProtectorTokenProvider<AppUser>
                      (dataProtectionProvider.Create("ConfirmationToken"))
                   {
                       TokenLifespan = TimeSpan.FromHours(3)
                   };
            }
    
            manager.EmailService = new EmailService();
    
            return manager;
        } //Create
      } //class
    } //namespace
    
    
  • トークンを生成するための私のActionは、(ここでトークンを確認しても、"Invalid token"のメッセージが出ます)。

    [AllowAnonymous]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult ForgotPassword(string email)
    {
        if (ModelState.IsValid)
        {
            AppUser user = UserManager.FindByEmail(email);
            if (user == null || !(UserManager.IsEmailConfirmed(user.Id)))
            {
                // Returning without warning anything wrong...
                return View("../Home/Index");
    
            } //if
    
            string code = UserManager.GeneratePasswordResetToken(user.Id);
            string callbackUrl = Url.Action("ResetPassword", "Admin", new { Id = user.Id, code = HttpUtility.UrlEncode(code) }, protocol: Request.Url.Scheme);
    
            UserManager.SendEmail(user.Id, "Reset password Link", "Use the following  link to reset your password: <a href=\"" + callbackUrl + "\">link</a>");
    
            //This 2 lines I use tho debugger propose. The result is: "Invalid token" (???)
            IdentityResult result;
            result = UserManager.ConfirmEmail(user.Id, code);
        }
    
        // If we got this far, something failed, redisplay form
        return View();
    
    } //ForgotPassword
    
    
  • トークンをチェックするための私のアクションは、(ここで、私は結果をチェックするときに常に"Invalid Token"を取得します)。

    [AllowAnonymous]
    public async Task<ActionResult> ResetPassword(string id, string code)
    {
    
        if (id == null || code == null)
        {
            return View("Error", new string[] { "Invalid params to reset password." });
        }
    
        IdentityResult result;
    
        try
        {
            result = await UserManager.ConfirmEmailAsync(id, code);
        }
        catch (InvalidOperationException ioe)
        {
            // ConfirmEmailAsync throws when the id is not found.
            return View("Error", new string[] { "Error to reset password:<br/><br/><li>" + ioe.Message + "</li>" });
        }
    
        if (result.Succeeded)
        {
            AppUser objUser = await UserManager.FindByIdAsync(id);
            ResetPasswordModel model = new ResetPasswordModel();
    
            model.Id = objUser.Id;
            model.Name = objUser.UserName;
            model.Email = objUser.Email;
    
            return View(model);
        }
    
        // If we got this far, something failed.
        string strErrorMsg = "";
        foreach(string strError in result.Errors)
        {
            strErrorMsg += "<li>" + strError + "</li>";
        } //foreach
    
        return View("Error", new string[] { strErrorMsg });
    
    } //ForgotPasswordConfirmation
    
    

何が足りないのか、何がいけないのか、わからない...。

どのように解決するのですか?

パスワードリセット用のトークンをここで生成しているためです。

string code = UserManager.GeneratePasswordResetToken(user.Id);

しかし、実際には電子メールのトークンを検証しようとしています。

result = await UserManager.ConfirmEmailAsync(id, code);

これらは2つの異なるトークンです。

質問では、電子メールを確認しようとしていると言っていますが、あなたのコードはパスワードリセットのためのものです。どちらをやっているのでしょうか?

電子メールの確認が必要な場合、トークンの生成は

var emailConfirmationCode = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);

で確認し

var confirmResult = await UserManager.ConfirmEmailAsync(userId, code);

パスワードのリセットが必要な場合は、このようにトークンを生成します。

var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);

というように、確認します。

var resetResult = await userManager.ResetPasswordAsync(user.Id, code, newPassword);