C# ';无效令牌。';通过电子邮件确认ASP.NET MVC时出错

C# ';无效令牌。';通过电子邮件确认ASP.NET MVC时出错,c#,asp.net,asp.net-mvc,asp.net-mvc-4,C#,Asp.net,Asp.net Mvc,Asp.net Mvc 4,我试图将注册和登录逻辑封装到MVC中的文件中。 一切正常,但我总是收到“无效令牌”。电子邮件确认过程后出错:( 求你了,你能帮我吗?我在搜索解决方案两天后快疯了 我注意到,GenerateEmailConfirmationToken方法总是生成不同的令牌,如日志文件中所示。可以吗?如果没有存储令牌,它应该总是相同的,对吗 以下是我的存储库构造器以及ASP.NET管理员的准备: UserStore<MyUser> store = null; UserManager<

我试图将注册和登录逻辑封装到MVC中的文件中。 一切正常,但我总是收到“无效令牌”。电子邮件确认过程后出错:(

求你了,你能帮我吗?我在搜索解决方案两天后快疯了

我注意到,
GenerateEmailConfirmationToken
方法总是生成不同的令牌,如日志文件中所示。可以吗?如果没有存储令牌,它应该总是相同的,对吗

以下是我的存储库构造器以及ASP.NET管理员的准备:

    UserStore<MyUser> store = null;
    UserManager<MyUser, string> userManager = null;
    SignInManager<MyUser, string> signInManager = null;
    IAuthenticationManager authenticationManager = null;
    AbstractLogger logger = AbstractLogger.GetInstance();

public MyUserRepository(MyDbContext context) : base(context)
        {
            store = new UserStore<MyUser>(context);
            userManager = new UserManager<MyUser>(store);

            authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
            signInManager = new SignInManager<MyUser, string>(userManager, authenticationManager);

            userManager.PasswordValidator = new PasswordValidator()
            {
                RequireDigit = false,
                RequiredLength = 6,
                RequireLowercase = false,
                RequireNonLetterOrDigit = false,
                RequireUppercase = false
            };

            userManager.UserValidator = new UserValidator<MyUser>(userManager)
            {
                RequireUniqueEmail = true,
                AllowOnlyAlphanumericUserNames = true
            };

            // Configure user lockout defaults
            userManager.UserLockoutEnabledByDefault = true;
            userManager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
            userManager.MaxFailedAccessAttemptsBeforeLockout = 5;

            userManager.EmailService = new EmailService();


            var provider = new DpapiDataProtectionProvider("MyApp.org");
            userManager.UserTokenProvider = new DataProtectorTokenProvider<MyUser, string>(provider.Create("UserToken")) as IUserTokenProvider<MyUser, string>;
        }
以下是日志输出:

USER: 1371ccfd-e8fd-46ed-8bfb-9d51f68aca63 

CODE: AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAADOWwoIJFDEqzZ8IvsDocNQAAAAACAAAAAAAQZgAAAAEAACAAAABakUsHl8hIMJX5U5sOc4zEgxUY8ikanoiKoZyIJkttZgAAAAAOgAAAAAIAACAAAADeBcyc9fhA+UR93KdPyWf8zzbJJjAcleIzf4CHCTr3OmAAAABUmOOqZs1FhaSRTcT2gV4V7JRhXNqYuJxJzB0gbo5DDfX1d010qH7YYNe4+iBh6JwdpKXR4tmsPKpojUx3RyPTbKIU8X39CJGqeWAFXAnDZMWKH2ztSn5M5h8V1zrotZRAAAAAVbRUJlIZeKgN/FH5//NQWRBFqKc9GSq0TvMWkYgZeAOyIfTh+JAMoXA4FrYnmJswLZC44zmlZPdisKnsT81ArA==

USER: 1371ccfd-e8fd-46ed-8bfb-9d51f68aca63 

CODE: AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAADOWwoIJFDEqzZ8IvsDocNQAAAAACAAAAAAAQZgAAAAEAACAAAABwzJP5VCa/GBicSwTV4Jwu2kt3XvX3xeklIFeJPiYB5QAAAAAOgAAAAAIAACAAAACfIv9bgzQJ9gwyc6Qhn/ml5iQU2qgvO83RiQGbEK/U32AAAACTT2WpFg2BdwLZzWI033SeNK3rUckzxkFkbeFGY7LlkuOhnrjsg/IMyv5YM8sFst8her1bPFi0NDvheSdIWIzWtBQFQZi2VuHRZz3+RiLQllIT/OS/94f1h+yx93QzIGhAAAAAVvPIboy1DrTKpv1easktkMW/olF+MT10MuNlQivcx5wDUSuvzql5GM6GY87Nkm1lFzp9+n0XNWEpbFRqilBuMA==

谢谢。问题确实出在编码上。
代码不应该每次都相同。

请使用Url.Action,而不是使用字符串连接创建Url.Url.Action在最新的MVC版本中在幕后进行编码,您可以避免编码和解码操作

下面是您可以使用的代码段

string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new
    {
        userId = user.Id,
        code = code,
        returnUrl = model.ReturnUrl
    }, protocol: Request.Url.Scheme);

如果不想使用
Url.Action
,则可以在生成Url时使用
HttpUtility.UrlEncode(code);
对令牌进行编码使用此
UserManager.GeneratePasswordResetTokenAsync
方法解决此问题

string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
return RedirectToAction("ResetPassword", "Account", new { userId = user.Id, code = code });

您需要关闭后验证,很抱歉,但我不明白…在第一个链接中,使用了GeneratePasswordResetToken。这不是我的情况。这也不是编码问题,因为每次代码都不同(请参阅日志)。
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new
    {
        userId = user.Id,
        code = code,
        returnUrl = model.ReturnUrl
    }, protocol: Request.Url.Scheme);
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
return RedirectToAction("ResetPassword", "Account", new { userId = user.Id, code = code });