Angularjs ASP.NET核心标识确认电子邮件上的无效令牌
这是一个与此非常相似的问题 但是这些解决方案无效,因为我正在使用新的ASP.NET Core 1.0,其中包含ASP.NET Core标识 我的设想如下:Angularjs ASP.NET核心标识确认电子邮件上的无效令牌,angularjs,asp.net-core,asp.net-identity,forgot-password,Angularjs,Asp.net Core,Asp.net Identity,Forgot Password,这是一个与此非常相似的问题 但是这些解决方案无效,因为我正在使用新的ASP.NET Core 1.0,其中包含ASP.NET Core标识 我的设想如下: 在后端(ASP.NET核心),我有一个功能,可以发送一封带有链接的密码重置电子邮件。为了生成链接,我必须使用Identity生成代码。像这样的 public async Task SendPasswordResetEmailAsync(string email) { //_userManager is an instance of U
public async Task SendPasswordResetEmailAsync(string email)
{
//_userManager is an instance of UserManager<User>
var userEntity = await _userManager.FindByNameAsync(email);
var tokenGenerated = await _userManager.GeneratePasswordResetTokenAsync(userEntity);
var link = Url.Action("MyAction", "MyController", new { email = email, code = tokenGenerated }, protocol: HttpContext.Request.Scheme);
//this is my service that sends an email to the user containing the generated password reset link
await _emailService.SendPasswordResetEmailAsync(userEntity , link);
}
CfDJ8JBnWaVj6h1PtqlmlJaH57r9TRA5j7Ij1BVyeBUpqX 5Cq1msu9zgkuI32Iz9x/5ue1b9fkfp4tzfy6btsedthsjx5c5cajptubivqichiwotodh4ei4 mokx7rdvbmhg4jozwqqtz5j30gxr/jmltbyxqop4jls8v05bekbv0bv0bvo/fsqqo5 jebokKkR5HEJU mqlnursjkkkkrbj9mufg8wqfg2fg2fg8bqqlj8bqlj2f8==
请注意,在有+
符号的地方,现在有了空格
符号,这显然会导致Identity认为标记是不同的。
出于某种原因,Angular正在以不同的编码方式解码URL查询参数
如何解决这个问题?这个答案为我指明了正确的方向。但正如我所说,这是一个不同的版本,现在它是略有不同的解决方案
答案仍然是一样的:在Base64URL中对令牌进行编码,然后在Base64URL中对其进行解码。这样,Angular和ASP.NET Core都将检索相同的代码
我需要安装另一个依赖项到Microsoft.AspNetCore.WebUtilities代码>
现在代码应该是这样的:
[HttpPut]
[AllowAnonymous]
[Route("api/password/{email}")]
public async Task<IActionResult> SendPasswordEmailResetRequestAsync(string email, [FromBody] PasswordReset passwordReset)
{
//some irrelevant validatoins here
await _myIdentityWrapperService.ResetPasswordAsync(email, passwordReset.Password, passwordReset.Code);
return Ok();
}
public async Task SendPasswordResetEmailAsync(string email)
{
//_userManager is an instance of UserManager<User>
var userEntity = await _userManager.FindByNameAsync(email);
var tokenGenerated = await _userManager.GeneratePasswordResetTokenAsync(userEntity);
byte[] tokenGeneratedBytes = Encoding.UTF8.GetBytes(tokenGenerated);
var codeEncoded = WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
var link = Url.Action("MyAction", "MyController", new { email = email, code = codeEncoded }, protocol: HttpContext.Request.Scheme);
//this is my service that sends an email to the user containing the generated password reset link
await _emailService.SendPasswordResetEmailAsync(userEntity , link);
}
公共异步任务SendPasswordResetEmailAsync(字符串电子邮件)
{
//_userManager是userManager的一个实例
var userEntity=await\u userManager.FindByNameAsync(电子邮件);
var tokenGenerated=wait_userManager.GeneratePasswordResetTokenAsync(userEntity);
byte[]tokenGeneratedBytes=Encoding.UTF8.GetBytes(tokenGenerated);
var codeconded=WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
var link=Url.Action(“MyAction”,“MyController”,新的{email=email,code=codeconded},协议:HttpContext.Request.Scheme);
//这是我的服务,它向用户发送一封包含生成的密码重置链接的电子邮件
wait_emailService.SendPasswordResetEmailAsync(userEntity,link);
}
以及在PUT请求期间接收回代码时
[HttpPut]
[AllowAnonymous]
[Route("api/password/{email}")]
public async Task<IActionResult> SendPasswordEmailResetRequestAsync(string email, [FromBody] PasswordReset passwordReset)
{
//some irrelevant validatoins here
await _myIdentityWrapperService.ResetPasswordAsync(email, passwordReset.Password, passwordReset.Code);
return Ok();
}
//in MyIdentityWrapperService
public async Task ResetPasswordAsync(string email, string password, string code)
{
var userEntity = await _userManager.FindByNameAsync(email);
var codeDecodedBytes = WebEncoders.Base64UrlDecode(code);
var codeDecoded = Encoding.UTF8.GetString(codeDecodedBytes);
await _userManager.ResetPasswordAsync(userEntity, codeDecoded, password);
}
[HttpPut]
[异名]
[路由(“api/密码/{email}”)]
公共异步任务SendPasswordEmailResetRequestAsync(字符串电子邮件,[FromBody]密码重置PasswordReset)
{
//这里有些不相干的东西
wait _myIdentityWrapperService.ResetPasswordAsync(电子邮件、passwordReset.Password、passwordReset.Code);
返回Ok();
}
//以我的身份为您服务
公共异步任务ResetPasswordAsync(字符串电子邮件、字符串密码、字符串代码)
{
var userEntity=await\u userManager.FindByNameAsync(电子邮件);
var codedecatedbytes=WebEncoders.Base64UrlDecode(代码);
var codeDecoded=Encoding.UTF8.GetString(codeDecodedBytes);
wait_userManager.ResetPasswordAsync(userEntity,codeDecoded,password);
}
我有一个类似的问题,我正在对我的令牌进行编码,但验证一直失败,问题是:options.LowercaseQueryStrings=true代码>
不要在选项上设置true
。LowercaseQueryStrings
这会改变验证令牌的完整性,您将得到无效令牌错误
// This allows routes to be in lowercase
services.AddRouting(options =>
{
options.LowercaseUrls = true;
options.LowercaseQueryStrings = false;
});
在我的Asp.NETCore3.0项目中搭建了ConfirmEmail页面之后,我遇到了同样的问题
从ConfirmEmail.cshtml.cs
中的OnGetAsync
方法中删除以下行修复了该问题:
code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
在脚手架登录页面中,将code
添加到callbackUrl
,然后使用HtmlEncoder.Default.Encode(callbackUrl)
对其进行URL编码。当点击链接时,解码会自动完成,code
就像确认电子邮件一样
更新:
我注意到在忘记密码的过程中,code
在放入callbackUrl
之前是Base64编码的,这意味着Base64解码是必要的
因此,更好的解决方案是在将代码添加到callbackUrl之前,将以下行添加到生成代码的任何位置
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
这里有一个到的链接,已经修复。我尝试了上面的答案,但这对我有所帮助。基本上,您需要对代码进行编码,否则会遇到一些奇怪的bug。总结一下,您需要这样做:
string code = HttpUtility.UrlEncode(UserManager.GenerateEmailConfirmationToken(userID));
在此之后,如果适用于您,请解码代码:
string decoded = HttpUtility.UrlDecode(code)
(据本报报道:)
对于resetPasswordAsync(标识管理器)“令牌无效”问题。。。因为“+”变成了url中的空格。。。
使用Uri.EscapeUriString
示例:在我的sendResetPasswordByMailAsync中
var token = "Aa+Bb Cc";
var encodedToken = Uri.EscapeDataString(token);
encodedToken=“Aa%20Bb2B%Cc”
var url=$”http://localhost:4200/account/reset-密码?email={email}&token={encodedToken}”;
var mailContent=$“请通过重置密码。”;
现在你可以点击你的链接,你将进入一个带有“+”的好网址(按%2B编码)。。。您的令牌不会无效…对于ASP Core 2.1也有类似的问题,这让我很头疼,因为代码的任何编码/解码(令牌
)对我都不起作用。对于userManager.confirmemailsync(用户,代码)
解决方案:
事实证明,问题在于,用户不是使用UserManager
创建的,而是使用dbcontext创建的,比如\u dbcontext.Users.AddAsync
,将此创建方法替换为\
var url = $"http://localhost:4200/account/reset-password?email={email}&token={encodedToken}";
var mailContent= $"Please reset your password by <a href='{url}'>clicking here</a>.";
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = user.Id, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
var decode = token.Replace(" ", "+");
await _userManager.ResetPasswordAsync(user, decode, Password);