Asp.net核心电子邮件确认有时显示InvalidToken

时间:2019-02-03 08:25:50

标签: c# asp.net asp.net-mvc .net-core asp.net-core-2.1

我正在使用asp.net核心身份2.1,并且电子邮件确认出现随机问题,而电子邮件确认有时会显示 result.Error = InvalidToken 。令牌也没有过期。

注意:我们正在使用多台服务器,并且还将密钥存储在一个位置,以便所有服务器都使用相同的密钥。

用于确认电子邮件的代码段。

电子邮件确认

var confCode = await _userManager.GenerateEmailConfirmationTokenAsync(user);
        var callbackUrl = Url.Action("ConfirmEmail", "Account", new
        {
            userId = user.Id,
            code = WebUtility.UrlEncode(confCode)
        }, protocol: HttpContext.Request.Scheme);

        string confirmationEmailBody = string.Format(GetTranslatedResourceString("ConfirmationEmailBody"), "<a href='" + callbackUrl + "'>") + "</a>";

令牌验证

public async Task<bool> ConfirmEmailAsync(string userId, string code)
    {
        if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(code))
            return false;


        var user = await _userManager.FindByIdAsync(userId);

        if (user == null)
            return false;

        var result = await _userManager.ConfirmEmailAsync(user, code).ConfigureAwait(false);

        if (!result.Succeeded)
            result = await _userManager.ConfirmEmailAsync(user, WebUtility.UrlDecode(code)).ConfigureAwait(false);

        return result.Succeeded;
    }

无效令牌

以下令牌被编码两次,但我们可以解决这种情况

CfDJ8HYrrpCgcr5GvrItPOWapXRy8WF8odd%252BVKuDup7buRsl1x4agRpfgQlEIPWiBqM0Wuilu9tCv5l%252B3lNaAb89%252Fi%252B4k0y%252FH0jdXAbabz0%252FXDGA0eUrmcKdIsDFNuXeyP5ezTVmTx8t0ky9xCTXaKLAfvTsCJviETk5Ag9JbUs3l3%252BnUon6fyYOHsslJI5VKLqhMM0Sm%252BW1EE%252B%252FPEJ%252BXcn%252FPS1My%252BI1lExuF1R1hFEZScEsUCG%252Bx%252BVIFB9bzs1IoLC%252Baw%253D%253D

任何帮助将不胜感激,谢谢!

7 个答案:

答案 0 :(得分:1)

此问题似乎是与查询字符串相关的基本问题。 您的问题中没有关于样本期望值和样本实际值的指示。因此,在这里我将无法为您提供确切的答案。但是下面的两个指针肯定会解决此问题。

可能有两个问题:

问题1:HtmlDecode / UrlDecode之后未还原原始Base-64

这些令牌被编码为以64为基的字符串,其中可能包含“ +”之类的字符。

它们被发送到服务器。

然后服务器尝试对此字符串执行HtmlDecode操作,以删除原始base 64令牌中实际存在的字符。

例如'+'替换为空字符串。

因此,在WebUtility.HtmlDecode之后生成的令牌无效。这就是为什么您会收到无效的令牌错误

的原因

How to check this ?您可以调试并查看HtmlDecode之后的值以及期望值。如果它们不同,那么这就是根本原因。

问题2:查询字符串格式不正确

查询字符串中的多个键值对使用'&'字符连接。 例如key1 = value1&key2 = value2

但是有时,它的编码版本&会代替&amp;出现在查询字符串中。
例如key1 = value1&key2 = value2

在这种情况下,.Net服务器将无法正确解析查询字符串。

How to check this ?您可以使用QueryString属性直接从HttpContext或HttpRequest中读取原始查询字符串,并检查是否存在这种情况。如果是,则可以更改客户端以发送适当的查询字符串(更具逻辑性和可维护性),也可以编写一些代码在服务器端进行更正。

这些指针应该可以帮助您解决问题。

答案 1 :(得分:0)

您的电子邮件确认请求将为您提供userId和Your Private key作为响应,但您的令牌方法应为不同的功能(如令牌刷新),您需要添加一些条件(如令牌已过期然后刷新令牌)

答案 2 :(得分:0)

这可能不是一个完美的答案,但是,如果您只需要紧急修复并且少了一些麻烦,请生成一个较短的无灾难性令牌/代码。

    services.AddIdentity<ApplicationUser, ApplicationRole>(options => {
        options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
        options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
    }).AddDefaultTokenProviders()
    .AddEntityFrameworkStores<YourDbContext>();

答案 3 :(得分:0)

您应先对确认码进行解码,然后再将其传递到_userManager.ConfirmEmailAsync(user, code).ConfigureAwait(false)方法中。

您已经用URL编码了在callBackUrl中使用的确认代码;您应先使用WebUtility.UrlDecode(code)对其进行解码,然后再尝试使用它。

答案 4 :(得分:0)

我认为用户创建过程花费了太多时间 单击之前,先确认 确保检查数据库已创建用户 检查确认电子邮件在sql表中为假

答案 5 :(得分:0)

您不需要使用身份服务器解决此问题。

当用户注册时,在用户表中添加两列。一个用于验证,其他用于IsVerified。在验证令牌列中添加一个Guid。然后使用此Guid生成一个链接。当用户单击此链接时,您会将Guid放入控制器内。然后使用此列吸引该用户,然后将IsVerified列设置为true并删除Guid列。现在,您的用户已成功验证。

答案 6 :(得分:0)

如果编码后的代码末尾包含“ ==”。即在urlencode或base64编码之后,如果代码像这样“ cm9vdA ==“。

对此进行解码将无法为您提供确切的编码字符串,并且会导致代码无效。

因此,在生成令牌时,请检查编码值是否以“ ==”结尾。如果它确实生成另一个令牌,则问题将得到解决。