我正在使用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
任何帮助将不胜感激,谢谢!
答案 0 :(得分:1)
此问题似乎是与查询字符串相关的基本问题。 您的问题中没有关于样本期望值和样本实际值的指示。因此,在这里我将无法为您提供确切的答案。但是下面的两个指针肯定会解决此问题。
可能有两个问题:
问题1:HtmlDecode / UrlDecode之后未还原原始Base-64
这些令牌被编码为以64为基的字符串,其中可能包含“ +”之类的字符。
它们被发送到服务器。
然后服务器尝试对此字符串执行HtmlDecode操作,以删除原始base 64令牌中实际存在的字符。
例如'+'替换为空字符串。
因此,在WebUtility.HtmlDecode之后生成的令牌无效。这就是为什么您会收到无效的令牌错误
的原因 How to check this ?
您可以调试并查看HtmlDecode之后的值以及期望值。如果它们不同,那么这就是根本原因。
问题2:查询字符串格式不正确
查询字符串中的多个键值对使用'&'字符连接。 例如key1 = value1&key2 = value2
但是有时,它的编码版本&
会代替&
出现在查询字符串中。
例如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 ==“。
对此进行解码将无法为您提供确切的编码字符串,并且会导致代码无效。
因此,在生成令牌时,请检查编码值是否以“ ==”结尾。如果它确实生成另一个令牌,则问题将得到解决。