Solución:
Esta respuesta https://stackoverflow.com/a/31297879/2948212 me señaló en la dirección correcta. Pero como dije, era para una versión diferente y ahora es una solución ligeramente diferente.
La respuesta sigue siendo la misma: codifique el token en la URL base 64 y luego descodifique en la URL base 64. De esa manera, tanto Angular como ASP.NET Core recuperarán el mismo código.
Necesitaba instalar otra dependencia para Microsoft.AspNetCore.WebUtilities;
Ahora el código sería algo como esto:
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);
}
y al recibir el código durante la solicitud 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);
}
Tuve un problema similar y estaba codificando mi token, pero seguía fallando la validación y el problema resultó ser este: options.LowercaseQueryStrings = true;
No ajuste true
sobre options.LowercaseQueryStrings
esto altera la integridad del token de validación y obtendrá un error de token no válido.
// This allows routes to be in lowercase
services.AddRouting(options =>
{
options.LowercaseUrls = true;
options.LowercaseQueryStrings = false;
});
Después de aplicar scaffolding a la página ConfirmEmail en mi proyecto Asp.Net Core 3.0, encontré el mismo problema.
Eliminando la siguiente línea del OnGetAsync
método en ConfirmEmail.cshtml.cs
solucionó el problema:
code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
En la página de inicio de sesión con scaffolding, el code
se agrega a la callbackUrl
que luego se codifica en URL usando HtmlEncoder.Default.Encode(callbackUrl)
. Cuando se hace clic en el enlace, la decodificación se realiza automáticamente y el code
es como debería ser para confirmar el correo electrónico.
ACTUALIZAR:
Me di cuenta de que durante el Has olvidado tu contraseña procesar el code
está codificado en Base64 antes de colocarse en el callbackUrl
lo que significa que la decodificación Base64 ES necesario.
Por lo tanto, una mejor solución sería agregar la siguiente línea donde se genere el código antes de agregarlo a callbackUrl.
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
Aquí hay un enlace al problema que se ha solucionado.