Successfully sending email but link is null - c#

I use Url.page() function but it always returning null value. I tried many times but it still return null value. My email is successfully sent but link is null.
var link = Url.Page("/Account/ConfirmEmailModel/",
pageHandler: null,
values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
protocol: Request.Scheme, Request.Host.ToString());
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", $"verify email.");

Related

Using UserManager to change the email of a user

I am trying to implement a feature to change the email of a user. Asp net core identity by default allows the user to change an email however it requires a confirmation link. I was wondering if it was possible to not use the confirmation link and just edit the function to update the email of the user with the new email. Thanks in advance
I have tried doing
await _userManager.ChangeEmailAsync(user, Input.NewEmail, code);
and
var changingser = _userManager.Users.First(u => u.Email.Equals(email));
changingser.Email = Input.NewEmail;
Which did not seem to work
Email.cshtml: Change Email function
public async Task<IActionResult> OnPostChangeEmailAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
if (!ModelState.IsValid)
{
await LoadAsync(user);
return Page();
}
var email = await _userManager.GetEmailAsync(user);
if (Input.NewEmail != email)
{
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
await _userManager.ChangeEmailAsync(user, Input.NewEmail, code);
/* var callbackUrl = Url.Page(
"/Account/ConfirmEmailChange",
pageHandler: null,
values: new { userId = userId, email = Input.NewEmail, code = code },
protocol: Request.Scheme);*/
//await _emailSender.SendEmailAsync(
// Input.NewEmail,
// "Confirm your email",
// $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
StatusMessage = "Email has been changed";
return RedirectToPage();
}
StatusMessage = "Your email is unchanged.";
return RedirectToPage();
}
Edit: Failed invalid token?
Yes, you can.
Use SetEmailAsync to see the user email.
This will still require the email to be 'confirmed' so generate a token, then immediately confirm the new email address.
Something like:
await _userManager.SetEmailAsync(user, Input.NewEmail);
var token = await _userManager.GenerateEmailConfirmationTokenAsync(existingUser);
await _userManager.ConfirmEmailAsync(existingUser, token);

_UserManager.CreateAsync() returns sucess but does not save the user on database

I am building a web app in .Net Core 3.0 and everything is running smooth but I found a small issue:
I have a method to create a user in a controller that runs well, saves the user and its all ok.
But I have the need to have another method in another controler that can also create users, and this method is copy / paste from the other working method that works, uses the same UserManager that is IOC'ed, it returns sucess, but at the end the user is not in the database.
This has to be in another method as this one if for creating users for other people, where the password is auto generated. The password passes and does not give any error on the createAsync() and it complies with the settings in the startup.cs file
I have changed the method, tryed to stimulate the EF context, to check if it was something on it, but no....
[HttpPut]
[Authorize(Roles = "Admin")]
[Route("CreateEmployee")]
public async Task<IActionResult> CreateEmployee([FromQuery]string email)
{
var user = new IdentityUser { UserName = email, Email = email };
var pw = UserHelper.GenerateRandomPassword(10);
var userResult = await _UserManager.CreateAsync(user, pw);
var resultRole = await _UserManager.AddToRoleAsync(user, "Employee");
var code = await _UserManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = user.Id, code = code },
protocol: Request.Scheme);
EmailSender sender = new EmailSender();
await sender.SendWelcomeEmailAsync("Email Header",
new NewUserData { ConfirmUrl = callbackUrl, Password = pw, Email = email, Username = $"" });
}
Inspecting the object userResult :
userResult .succeded = true
uuserResult er.Errors.Count = 0
Inspecting the object resultRole :
resultRole.succeded = true
resultRole.Errors.Count = 0

Why my email confirmation token is invalid?

I'm trying to get clean emailconfirmation on Microsoft Identity 2.0. I'm generating email link for confirmation and it's not working.
I found, that encoded token on callbackrul is changing to lowercase and I believe that there is a problem. But I don't know how to solve it.....
When code variable gets value it looks like:
CfDJ8C5jg3XNISFEoFA015AdmTmmbOmQG/cxNBfdOALg4WM+iU6uf8WeJ13buFIzbdlP3tK3kWU1Q6BwGh/DY7dAYqbj+zz7jXGOK1Y79mtDT2jiEKV4NdaLbfaruzOvoKSVhvg4EFVYPAQRrjcAnOkfCxlff6hMVhIBWHkg8rqv7GBnqXvJ+UbCErqlobIxI69YreNWVTM1Z4lkAYQM2xmwRA//0T53KNPTWIX52oDc52eFLJAlsWhXI9uHwgfwTt0X9g==
After callback it's changed to:
cfdj8c5jg3xnisfeofa015admtmmbomqg%2Fcxnbfdoalg4wm%2Biu6uf8wej13bufizbdlp3tk3kwu1q6bwgh%2Fdy7dayqbj%2Bzz7jxgok1y79mtdt2jiekv4ndalbfaruzovoksvhvg4efvypaqrrjcanokfcxlff6hmvhibwhkg8rqv7gbnqxvj%2Bubcerqlobixi69yrenwvtm1z4lkayqm2xmwra%2F%2F0t53knptwix52odc52efljalswhxi9uhwgfwtt0x9g%3D%3D
On confirmation action I'm getting decoded token as:
cfdj8c5jg3xnisfeofa015admtmmbomqg/cxnbfdoalg4wm+iu6uf8wej13bufizbdlp3tk3kwu1q6bwgh/dy7dayqbj+zz7jxgok1y79mtdt2jiekv4ndalbfaruzovoksvhvg4efvypaqrrjcanokfcxlff6hmvhibwhkg8rqv7gbnqxvj+ubcerqlobixi69yrenwvtm1z4lkayqm2xmwra//0t53knptwix52odc52efljalswhxi9uhwgfwtt0x9g==
Part of register.cshtml.cs
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = user.Id, code = codeenc },
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>.");
confirmemail.cshtml.cs
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return NotFound($"Unable to load user with ID '{userId}'.");
}
var result = await _userManager.ConfirmEmailAsync(user, code);
So where I make a mistake?
I'm not sure but did you try this one? code = System.Web.HttpUtility.UrlEncode(code);
Problem was in my startup.cs file,
options.LowercaseQueryStrings = true;
After comment token is working ok.

Register user with identity

I'm in a project where only administrators can add new members to the system. But I'm getting the following error:
The data protection operation was unsuccessful. This may have been caused by not loading the user profile into the user context of the current thread, which can happen when the thread is impersonating.
Description: An unhandled exception occurred during the execution of the current WEB request. Examine the stack trace for more information about the error and where it originated in the code.
Exception Details: System. Security. Cryptography. Cryptographicexception: The data protection operation was unsuccessful. This may have been caused by not loading the user profile into the user context of the current thread, which can happen when the thread is impersonating.
The problem only happens after the project is published.
My Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model, HttpPostedFileBase AvatarAux = null)
{
ClaimsIdentity identity = (ClaimsIdentity)User.Identity;
string idRepresentanteLogado = identity.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid).Value;
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
IsInativo = model.IsInativo,
DataCadastro = model.DataCadastro,
Nome = model.Nome,
Id_Tipo_Representante = model.Tipo_Representante.Id,
UserResponsavel = _userManager.FindById(idRepresentanteLogado),
Avatar = AvatarAux != null ? ImagemConverter.ImagemToByte(AvatarAux) : ImagemConverter.ObterImagemUsuarioDefault(),
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code }, protocol: Request.Url.Scheme);
await _userManager.SendEmailAsync(user.Id, "Confirme sua Conta", "Por favor confirme sua conta clicando neste link: <a href='" + callbackUrl + "'></a>");
ViewBag.Link = callbackUrl;
return View("DisplayEmail");
}
AddErrors(result);
return View(model);
}
I managed to get around the problem by commenting on the following code:
if (result.Succeeded)
{
//var code = await _userManager.GenerateEmailConfirmationTokenAsync(user.Id);
//var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code }, protocol: Request.Url.Scheme);
//await _userManager.SendEmailAsync(user.Id, "Confirme sua Conta", "Por favor confirme sua conta clicando neste link: <a href='" + callbackUrl + "'></a>");
//ViewBag.Link = callbackUrl;
return RedirectToAction("ListUsers", "Account");
}

ASP.NET Core invalid token when confirming email but token seems valid

I have ASP.NET Core web api project and I need to confirm email. Everything is working fine and generated token and token received in ConfirmEmail() method are equal. Token seems valid but result gives invalid token:
var result = await userManager.ConfirmEmailAsync(user, code);
Generating token:
var code = await userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
var email = user.Email;
await emailSender.SendEmailConfirmationAsync(email, callbackUrl);
EmailConfirmationLink() and SendEmailConfirmationAsync() methods:
public static string EmailConfirmationLink(this IUrlHelper urlHelper, string userId, string code, string scheme)
{
var result = urlHelper.Action(
action: "ConfirmEmail",
controller: "ApplicationUsers",
values: new { userId, code },
protocol: scheme);
return result;
}
public static Task SendEmailConfirmationAsync(this IEmailSender emailSender, string email, string link)
{
return emailSender.SendEmailAsync(email, "Confirm your email",
$"Please confirm your account by clicking this link: <a href='{HtmlEncoder.Default.Encode(link)}'>Confirm email</a>");
}
ConfirmEmail() method:
public async Task<IActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
// ....
}
var user = await userManager.FindByIdAsync(userId);
if (user == null)
{
throw new ApplicationException($"Unable to load user with ID '{userId}'.");
}
var result = await userManager.ConfirmEmailAsync(user, code);
I was also having this issue and i tried the answers above and till got no luck.
Setting the isHtml parameter to true in the SendAsync method fixed my problem.
_emailService.SendAsync(vm.Email, "Click the link below to validate.", $"Validate email",true);

Categories