I'm trying to give my users the ability to change email. I'd like to send a verification email as well, in which they can verify/confirm their email.
I'd just like to know more about the flow of this, and I haven't been able to find reasonable documentation online.
I see the flow like this:
User enters the new email they wish to use
Code/Token is created together with the confirmation email (the new email is not yet applied to the user)
Confirmation email is sent to the new email
User confirms/verifies their new email
New email and code is received in the controller and the UserManager.ChangeEmailAsync(User user, string newEmail, string code) is invoked
Is the new email applied to the user when the ChangeEmailAsync() method is invoked, or do I have to apply the new email before sending the confirmation email (set EmailConfirmed back to false)?
try this:
tring code = await UserManager.GenerateUserTokenAsync("ChangeEmail",userID);
in SendingEmail() to the new email and save the new email in a temporary table
the function when the user confirm the new e-mail:
`
public async Task<IHttpActionResult> ChangeEmail(ChangeEmailModel model)
{
try
{
HttpUtility.UrlEncode(model.Code);
if ( !UserManager.VerifyUserToken(model.UserId, "ChangeEmail", model.Code)) //to verify the code
{
_logger.Error($"token expired");
return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, new KeyValuePair<String, String>(Messages.ExpiredLink, CommonMessages.ExpiredLink)));
}
else
{
UserDetailsManager userDetailsManager = new UserDetailsManager();
string Email = userDetailsManager.GetNewEmail(model.UserId);//get the new email from the temporary table
var user = await UserManager.FindByIdAsync(model.UserId);
user.Email = Email;//change the email
user.UserName = Email;
result = await UserManager.UpdateAsync(user);
if (!result.Succeeded)
{
foreach (var item in result.Errors)
{
if (item.Contains("already"))
{
_logger.Info("In ChangeEmail user already exists");
return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, new KeyValuePair<String, String>(Messages.EmailUserExist, CommonMessages.EmailUserExist)));
}
}
}
}
}
}
catch (Exception ex)
{
_logger.Error($"In ChangeEmail Error - {ex.Message} return {HttpStatusCode.InternalServerError}");
return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, new KeyValuePair<String, String>(Messages.InternalServerError, CommonMessages.InternalServerError)));
}
_logger.Info($"ChangeEmail end status {HttpStatusCode.OK} ");
return Ok("Success");
}`
this function also Overrides the preoccupation with the confirmEmail
Related
I am using Firebase to allow the user to login to a Unity game via Facebook. It is working fine, but I cannot get access to the user's email by using this parameter auth.CurrentUser.Email. Also, the email is not stored in Firebase Authentication Console. The email can be stored/accessed succussfully when I use other sign-in methods, such as email and google.
Here is my code:
public void SignInFacebook()
{
var perms = new List<string>() { "public_profile", "email", "user_friends" };
FB.LogInWithReadPermissions(perms, AuthCallback);
}
private void AuthCallback(ILoginResult result)
{
if (FB.IsLoggedIn)
{
// AccessToken class will have session details
var aToken = Facebook.Unity.AccessToken.CurrentAccessToken;
// Print current access token's User ID
Debug.Log(aToken.UserId);
// Print current access token's granted permissions
foreach (string perm in aToken.Permissions)
{
Debug.Log(perm);
}
Credential credential = FacebookAuthProvider.GetCredential(aToken.TokenString);
auth.SignInWithCredentialAsync(credential).ContinueWithOnMainThread(task => {
if (task.IsCanceled)
{
Debug.LogError("SignInWithCredentialAsync was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("SignInWithCredentialAsync encountered an error: " + task.Exception);
return;
}
Firebase.Auth.FirebaseUser newUser = task.Result;
Debug.LogFormat("User signed in successfully: {0} - {2} - ({1})",
newUser.DisplayName, newUser.UserId, newUser.Email);
});
}
else
{
Debug.Log("User cancelled login");
}
}
And this is what it looks like in the console ("-" is where the email is supposed to be stored. If I use another sign-in method, such as email or google, the email is stored without any issues)
Similar questions were asked about this issue and it was suggested that I change the Account email address setting in Firebase to Prevent creation of multiple accounts with the same email address, but it did not solve the issue.
Thanks!
If your Facebook app is in test mode you must login from your Facebook ID. Go to the settings, scroll down, select Apps and Websites, and click on your app. From there, make sure email address require is enabled.
you can try this
private void FacebookAuthCallback(ILoginResult result)
{
if (FB.IsLoggedIn)
{
FB.API("/me?fields=id,name,email", HttpMethod.GET, FacebookGetInfo);
}
else
{
Debug.Log("User cancelled login");
}
}
private void FacebookGetInfo(IResult result)
{
if (result.Error == null)
{
if (result.ResultDictionary.ContainsKey("email"))
{
string aEmail = result.ResultDictionary["email"].ToString();
return;
}
}
else
{
Debug.Log(result.Error);
}
}
I'm hey one of the most weirdest problems i have seen until now. I have the same peace of code the SMTP client. I have it in a separate class that handles sending emails so this is the constructor`
// Setting the smtp info
smtpClient = new SmtpClient("xxxxxxx", 587);
// Setting the no reply email address
smtpClient.Credentials = new NetworkCredential("xxxxxxxxx", "xxxxx");
FromMailAddress = new MailAddress("xxxxxxxxx", "xxxxxxxx");
// Setting Ssl
smtpClient.EnableSsl = true;`
And this is for sending the Email:
// Setting a new email address for the recver
MailAddress reciver = new MailAddress("xxxxxxxx");
// Creating a new Email message
MailMessage email = new MailMessage();
email.IsBodyHtml = true;
email.To.Add(reciver);
email.From = FromMailAddress;
email.Subject = "Email confomation link";
email.Body = "Please Fonfurm your email by pressing this link: link";
smtpClient.Send(email);
Sorry i really needed to block out some stuff. But this code works in a test application that i made in just simple comandline C# application. Now comes the strange thing when i call it in a simple ActionResult that i created for this it works but when i call it in Register method it fails it says time out, and for the rest it does not give anymore information. Here is the test method i created:
public ActionResult SendTestEmail()
{
new EmailManager().SendEmailConfirmation("xxxxxxxx", "Hello world");
return RedirectToAction("Index");
}
Quite simple and it works but when i put it like this it fails:
public async Task<ActionResult> Register(RegisterViewModel model)
{
// Check if model is valled And if we have a id
if (ModelState.IsValid && !String.IsNullOrEmpty(model.RegisterCode))
{
ApplicationUser user = new ApplicationUser { UserName = model.UserName, Email = model.Email.ToLower() };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// Sing in
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// Add the members role to the user
UserManager.AddToRole(user.Id, "Member");
// Createing a token for email confermation
string emailCode = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// Createing a URL
string callbackUrl = Url.Action(
"ConfirmEmail",
"Account",
new { userId = user.Id, code = emailCode },
protocol: Request.Url.Scheme
);
// Sending the email
new EmailManager().SendEmailConfirmation(model.Email, callbackUrl);
// delete the registion code form the database
GenerateCodeManager.DeleteFromCodeFromDatabase(model.RegisterCode);
// Return to index
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
return View(model);
}
And than we have a problem it fails. I really dont know why i think this also might the problem why my web server is also not sending emails. i use the SMTP of zoho That is this SMTP smtp.zoho.eu Like i said it works but not in this method.
I am creating a small demo for reset password in web API and identity using in .net MVC c#.and I am clicking on forgot password send one code in the mail using a query string. In the mail code is correct getting. now I am going for the change password and getting the code from the URL not getting propare in the token '==' last end not getting and get error invalid token how can do fix it this error anyone knows?
this my ForgotPassword method in Account Controller :
public async Task<IHttpActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
try
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null)
{
return Ok();
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
await UserManager.SendEmailAsync(user.Id, "Reset Password",Request.RequestUri.GetLeftPart(UriPartial.Authority) + "/home/ChangePassword?Code=" + code);
return Ok("Ok");
}
catch (Exception ex)
{
ExceptionsLogging.SendExcepToDB(ex);
throw new HttpException(500, ex.Message);
}
}
this is my ResetPasswordMethod :
public async Task<IHttpActionResult> ResetPassword(ChangePasswordBindingModel model)
{
try
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return Ok();
}
var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.NewPassword); // here not getting code propare
if (result.Succeeded)
{
return Ok("Done");
}
return Ok();
}
catch (Exception ex)
{
ExceptionsLogging.SendExcepToDB(ex);
throw new HttpException(500, ex.Message);
}
}
any one know how can fix it i am try encode/decode but now getting propare
You must encode the generated token before sending the email
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var encodedCode = HttpUtility.UrlEncode(code);
await UserManager.SendEmailAsync(user.Id, "Reset Password",Request.RequestUri.GetLeftPart(UriPartial.Authority) + "/home/ChangePassword?Code=" + encodedCode);
return Ok("Ok");
I have an mvc application that uses gmail to send out an email.
My code:
Successfully sends out an email, providing:
I use proper account authentication (username, pw)
I send the email to a valid existing email account
I get an exception if I do not use my valid gmail username, pw. (which is good).
My question and my problem is:
When my code sends an email to an invalid email account, I do not get an exception of any kind! No SmtpFailedRecipientException, no SmtpFailedRecipientsException; nada.
Why is this happening? What do I need to change so that I get an exception back when an email is sent to an invalid, non-existent account?
Code in my MVC app:
In Identity.cs
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
try
{
System.Web.Helpers.WebMail.Send(message.Destination, message.Subject, message.Body, "DoNotReply#ourcompany.com");
}
catch (Exception e)
{
throw; //Add msg here; set break point when testing; whatever
}
return Task.FromResult(0);
}
}
And in AuthConfig.cs, I have the gmail account settings, which we know work.
System.Web.Helpers.WebMail.SmtpServer = "smtp.gmail.com";
WebMail.EnableSsl = true;
WebMail.UserName = "OurUserName";
WebMail.Password = "OurPW";
WebMail.From = "DoNotReply#OurCompany.com";
WebMail.SmtpPort = 587;
In my controller, I have this partial code:
public async Task<ActionResult> Register(RegisterViewModel model)
{
try
{
await UserManager.SendEmailAsync(user.Id, emailSubject, emailBody);
}
catch (Exception e)
{
}
}
The controller runs first. I am using the asp.identity2 (UserManager) and SendEmailAsync calls the SendAsync in Identity.cs.
Thank you for suggestions.
Gmail doesn't let you know which email addresses it has failed to send emails to to avoid bots looking for valid email addresses. You should get an email later though with details about failed email addresses.
I created MVC 4 application. In that application If user forgot the password I have method to send an email to user to reset password. I'm using asp.net Identity membership
I'm getting following error message when I deploy this project in web server. Its working perfectly in my localhost mode.
Error Message
Cannot edit this User The data protection operation was unsuccessful.
This may have been caused by not having the user profile loaded for
the current thread's user context, which may be the case when the
thread is impersonating.!
this is the forgot password method
[AllowAnonymous]
public ActionResult ForgotPassword()
{
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (model.UserName == null)
{
ModelState.AddModelError("", "Please enter the Username");
}
if (model.Email == null)
{
ModelState.AddModelError("", "Please enter the Email ID");
}
if (model.Email == null & model.UserName == null)
{
ModelState.AddModelError("", "Please enter the Username and Email ID");
}
if(ModelState.IsValid)
{
var username = await UserManager.FindByNameAsync(model.UserName);
var user = await UserManager.FindByEmailAsync(model.Email);
if (user != null && username != null)
{
ApplicationDbContext context = new ApplicationDbContext();
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>(context);
var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("MyProject");
UserManager.UserTokenProvider = new Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider<ApplicationUser>(provider.Create("EmailConfirmation"));
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
System.Net.Mail.MailMessage m = new System.Net.Mail.MailMessage(
new System.Net.Mail.MailAddress("sample#email.lk", "My Application"),
new System.Net.Mail.MailAddress(user.Email));
m.Subject = "Reset your Password";
m.IsBodyHtml = true;
m.Body = string.Format("<img src=\"##IMAGE##\" alt=\"\"><BR/><BR/>Hi {0},<BR/><BR/>Please click the below link to reset your password. <BR/><BR/> Reset Password", user.UserName, Url.Action("ResetPassword", "Account", new { UserId = user.Id, code = code }, Request.Url.Scheme)) + string.Format("<BR/><BR/>Regards,<BR/>We Are <BR/>");
string attachmentPath = Server.MapPath("~/Images/hec-logo.png");
string contentID = Path.GetFileName(attachmentPath).Replace(".", "") + "#zofm";
Attachment inline = new Attachment(attachmentPath);
inline.ContentDisposition.Inline = true;
inline.ContentDisposition.DispositionType = DispositionTypeNames.Inline;
inline.ContentId = contentID;
inline.ContentType.MediaType = "image/png";
inline.ContentType.Name = Path.GetFileName(attachmentPath);
m.Attachments.Add(inline);
// replace the tag with the correct content ID
m.Body = m.Body.Replace("##IMAGE##", "cid:" + contentID);
System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient("11.11.11.111");
smtp.Port = 11;
smtp.Credentials = new System.Net.NetworkCredential("sample#email.lk", "8888888");
smtp.EnableSsl = false;
smtp.Send(m);
// Don't reveal that the user does not exist or is not confirmed
}
return View("ForgotPasswordConfirmation");
}
else
{
ModelState.AddModelError("", "The Username or Email ID is invalid.");
}
// If we got this far, something failed, redisplay form
return View(model);
}
I had same issue , then after many research I found out that problem is in IIS deployment
so following this thread I able to fix my issue
The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread’s user context, which may be the case when the thread is impersonating.
Open your IIS Manager
Find out what AppPool your application is using by selecting your App, right-click on it, and Select Manage Application -> Advanced
Settings.
After that, on the top left hand side, select Applications Pools, and go ahead and select the App Pool used by your app.
Right-click on it, and select Advanced Settings, Go to the Process Model Section and Find the “Load User Profile” Option and set it to
true.