Im trying to send an email to a user when they have forgot their password in a mvc app this is my code.pls help
this is my email class in my businesslogic
public class EmailBusiness
{
public bool SendEmailForgot(string email, string url)
{
bool isvalid = false;
try
{
var boddy = new StringBuilder();
boddy.Append("Hi! " + email + "<br/>");
boddy.Append("Click the link to reset your " + url);
string bodyFor = boddy.ToString();
string toFor = email;
const string subjectFor = "Reset Password";
WebMail.SmtpServer = "pod51014.outlook.com";
WebMail.SmtpPort = 587;
WebMail.UserName = "20822526#dut4life.ac.za";
WebMail.Password = "Password";
WebMail.From = "20822526#dut4life.ac.za";
WebMail.EnableSsl = true;
WebMail.Send(to: toFor, subject: subjectFor, body: bodyFor);
isvalid = true;
return isvalid;
}
catch
{
return isvalid;
}
}
this is my forgotpassword model in my Accountviewmodels
public class ForgotPasswordViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
}
this is my forgotpassword action in accountcontroller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model, string sms)
{
EmailBusiness _emailBusiness = new EmailBusiness();
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
// 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);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here");
_emailBusiness.SendEmailForgot(model.Email, callbackUrl);
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
// If we got this far, something failed, redisplay form
return View(model);
}
and this is my view
#model Template.Model.ForgotPasswordViewModel
#{
ViewBag.Title = "Forgot your password?";
Layout = "~/Views/shared/_BootstrapLayout.basic.cshtml";
}
<h2>#ViewBag.Title.</h2>
#using (Html.BeginForm("ForgotPassword", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Enter your email.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Email Link" />
</div>
</div>
}
and this in my webconfig
<appSettings>
<add key="from" value="20822526#dut4life.ac.za" />
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
Related
I want to redirect the user to another page when he is logged. I try this solution but the actual page is loading and not redirecting to other page.
The Address Bar conatin a new # at the end.
This is my code in Controller :
[HttpPost]
public ActionResult Login(FormCollection fc)
{
int res = dblayer.Admin_Login(fc["Email"], fc["Password"]);
if (res == 1)
{
return View("~/Views/Client/Edit.cshtml");
}
else {
return View("~/Views/Client/Create.cshtml");
}
return View();
}
and this what I have wrote in View :
<div class="login" id="login">
<div class="main-w3l">
<div class="w3layouts-main" style="background-image:url('/template/web/images/bg3.jpg'); margin-top:50px;">
<h2>Login Now</h2>
#using (Html.BeginForm("Login", "Home", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
}
<form action="#" method="post">
<input value="E-MAIL" name="Email" type="email" required="" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'E-Mail';}" />
<input value="PASSWORD" name="Password" type="password" required="" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'password';}" />
<span><input type="checkbox" />Remember Me</span>
<h6>Forgot Password?</h6>
<div class="clear"></div>
<input type="submit" value="login" name="login">
</form>
<p>Don't Have an Account ?Register Now</p>
</div>
</div>
and this is my db.cs :
public int Admin_Login(string Email, string Password)
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["DeliveryCon"].ConnectionString)) {
int res = 0;
SqlCommand com = new SqlCommand("SP_Login", con);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#Email", Email);
com.Parameters.AddWithValue("#Password", Password);
SqlParameter oblogin = new SqlParameter();
oblogin.ParameterName = "#Isvalid";
oblogin.SqlDbType = SqlDbType.Bit;
oblogin.Direction = ParameterDirection.Output;
com.Parameters.Add(oblogin);
con.Open();
com.ExecuteNonQuery();
res = Convert.ToInt32(oblogin.Value);
return res;
}
}
the problem persist when I ve tried to test using Javascfript like this :
[HttpPost]
public ActionResult Login(FormCollection fc)
{
int res = dblayer.Admin_Login(fc["Email"], fc["Password"]);
if (res == 1)
{
TempData["msg"] = " Login Successful !";
}
else {
TempData["msg"] = " Email or Password is wrong !";
}
return View();}
#{
if (TempData["msg"] != null)
{
<script type="text/javascript">
alert('#TempData["msg"]');
</script>
}
}
Instead of returning a View(); try doing this
return RedirectToAction("Client","Edit",new { Id= id});
This assumes that you have a Client controller with a Edit action that requires an Id parameter which you most likely do.
Try the following:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(FormCollection fc)
{
int res = dblayer.Admin_Login(fc["Email"], fc["Password"]);
if (res == 1)
{
return RedirectToAction("Edit");
}
else
{
return RedirectToAction("Create");
}
}
public ActionResult Create()
{
return View();
}
public ActionResult Edit()
{
return View();
}
Take a look at this tutorial, it covers a lot of the basic stuff you will need to develop this:
https://learn.microsoft.com/en-us/aspnet/mvc/overview/security/create-an-aspnet-mvc-5-web-app-with-email-confirmation-and-password-reset
Use this for redirection
return RedirectToAction("Edit","Client");
You need to changes your view
<div class="login" id="login">
<div class="main-w3l">
<div class="w3layouts-main" style="background-image:url('/template/web/images/bg3.jpg'); margin-top:50px;">
<h2>Login Now</h2>
#using (Html.BeginForm("Login", "Home", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<input value="E-MAIL" name="Email" type="email" required="" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'E-Mail';}" />
<input value="PASSWORD" name="Password" type="password" required="" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'password';}" />
<span><input type="checkbox" />Remember Me</span>
<h6>Forgot Password?</h6>
<div class="clear"></div>
<input type="submit" value="login" name="login">
}
<p>Don't Have an Account ?Register Now</p>
</div>
</div>
I have modified the Views/Manage/Index.cshtml to display the User's email as well. I've modified the IndexViewModel as well so it recognizes the "Email" string and then made another .cshtml page similar to the changing of phone number one which is there by default. The new page is called ChangeEmail.cshtml
#using (Html.BeginForm("ChangeEmail", "Manage", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Add an email</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
From what I've seen, the changing of password happens through a task called "ChangePasswordAsync" inside UserManager.cs
Is there a way to change the Email without making a new task?
EDIT: added more from the controller(index) :
public async Task<ActionResult> Index(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
: message == ManageMessageId.Error ? "An error has occurred."
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
: message == ManageMessageId.EmailChangedSuccess ? "Your email has been changed"
: "";
var userId = User.Identity.GetUserId();
var userEmail = User.Identity.Name;
var user = UserManager.FindById(userId);
var model = new IndexViewModel
{
HasPassword = HasPassword(),
PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
Logins = await UserManager.GetLoginsAsync(userId),
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId),
Email = user.Email,
City = user.City,
Region = user.Region
};
user.Email = "topkek#ucn.dk";
UserManager.UpdateAsync(user);
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ChangeEmail(ChangeEmailViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
return RedirectToAction("Index", new { Message = ManageMessageId.EmailChangedSuccess });
}
Get the user's Email address from your ChangeEmailViewModel and then update the user's details using the userManager.UpdateAsync(user)
EDIT
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ChangeEmail(ChangeEmailViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
//Get the user's Id
var userId = User.Identity.GetUserId();
//get the user (you can modify the variables to fit yours)
var user = UserManager.FindByIdAsync(userId);
//this is how to change the Email
user.Result.Email= model.Email// **EDIT**;
userManager.UpdateAync(user.Result);
return RedirectToAction("Index", new { Message = ManageMessageId.EmailChangedSuccess });
}
I am developing a basic web site in ASP.NET MVC 5 (using visual studio 2013). The site will use Facebook for user authentication and for retrieving initial profile data.like stack over flow login with facebook..access user name,profile photo etc..plz any one help me relevant sample
startup.auth.cs
FacebookAuthenticationOptions fbao = new FacebookAuthenticationOptions();
fbao.AppId = "****";
fbao.AppSecret = "*****";
fbao.Scope.Add("email");
fbao.Scope.Add("user_birthday");
fbao.Scope.Add("user_hometown");
fbao.SignInAsAuthenticationType = Microsoft.Owin.Security.AppBuilderSecurityExtensions.GetDefaultSignInAsAuthenticationType(app);
app.UseFacebookAuthentication(fbao);
Account controller>>Externallogincallback
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
ClaimsIdentity fboa = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
//var email = ext.Claims.First(x => x.Type.Contains("emailaddress")).Value;
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
// Sign in the user with this external login provider if the user already has a login
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
case SignInStatus.Failure:
default:
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
}
}
Account view model
public class ExternalLoginConfirmationViewModel
{
[Required]
[Display(Name = "Email")]
public string Email { get; set; }
public string UserName { get; set; }
}
externalloginconfirmationview
<h4>Association Form</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<p class="text-info">
You've successfully authenticated with <strong>#ViewBag.LoginProvider</strong>.
Please enter a user name for this site below and click the Register button to finish
logging in.
</p>
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.UserName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.UserName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
Following are some nice tutorials that may help solve your issue
http://www.asp.net/mvc/overview/security/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on
http://www.asp.net/mvc/overview/getting-started/aspnet-mvc-facebook-birthday-app
I've created a new Web Forms Project in visual studio 2013 and I want users to be able to login using their UserName(eg. administrator) not their email address.
If you open the automatically generated "Register.aspx.cs" file you'll see this piece of code:
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = Context.GetOwinContext().Get<ApplicationSignInManager>();
var user = new ApplicationUser() { UserName = Email.Text, Email = Email.Text };
Question:
Why does the UserName and Email have the same value on last line??? In this case why do you need UserName column since you have already Email column?
Is possible to login using username not email address?
I'm trying to solve this by adding a new textbox field to registration form called "UserName":
Register.aspx
<div class="form-group">
<asp:Label runat="server" AssociatedControlID="UserName" CssClass="col-md-2 control-label">UserName</asp:Label>
<div class="col-md-10">
<asp:TextBox runat="server" ID="UserName" CssClass="form-control" />
<asp:RequiredFieldValidator runat="server" ControlToValidate="Email"
CssClass="text-danger" ErrorMessage="The UserName field is required." />
</div>
</div>
And on the Register function I've made this change:
Register.aspx.cs
var user = new ApplicationUser() { UserName = UserName.Text, Email = Email.Text };
Then I've changed the login function like this:
Login.aspx.cs
protected void LogIn(object sender, EventArgs e)
{
if (IsValid)
{
// Validate the user password
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signinManager = Context.GetOwinContext().GetUserManager<ApplicationSignInManager>();
// This doen't count login failures towards account lockout
// To enable password failures to trigger lockout, change to shouldLockout: true
//var result = signinManager.PasswordSignIn(Email.Text, Password.Text, false, shouldLockout: false);
SignInStatus result = SignInStatus.Failure;
// check too see if the user has entered a email address or not
if (IsValidEmail(NameOrEmail.Text))
{
result = signinManager.PasswordSignIn(NameOrEmail.Text, Password.Text, false, shouldLockout: false);
}
else
{
// get users email using his name
var user = manager.FindByName(NameOrEmail.Text);
result = signinManager.PasswordSignIn(user.Email, Password.Text, false, shouldLockout: false);
}
switch (result)
{
case SignInStatus.Success:
string queryString = Request.QueryString["ReturnUrl"];
if (!string.IsNullOrEmpty(queryString))
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
else
Response.Redirect("/Account/Dashboard");
break;
case SignInStatus.LockedOut:
Response.Redirect("/Account/Lockout");
break;
case SignInStatus.Failure:
default:
FailureTextLabel.Text = "Invalid login!";
ErrorMessage.Visible = true;
break;
}
}
}
// check email address
private bool IsValidEmail(string strIn)
{
// Return true if strIn is in valid e-mail format.
return Regex.IsMatch(strIn, #"^([\w-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
}
And the template looks like this:
Login.aspx
<div class="form-group">
<asp:Label runat="server" AssociatedControlID="NameOrEmail" CssClass="col-md-2 control-label">UserName or Email</asp:Label>
<div class="col-md-10">
<asp:TextBox runat="server" ID="Email" CssClass="form-control" />
<asp:RequiredFieldValidator runat="server" ControlToValidate="NameOrEmail"
CssClass="text-danger" ErrorMessage="The name or email field is required." />
</div>
</div>
The problem:
If you change the UserName on Register you cannot login anymore(you'll get SignInStatus.Failure).
Seems to me that the UserName has to be the same as Email on registration for the login to work.
Is there a way to solve this?
First of all this isn't a bug at all. This is how it works, if you want to use out of the box default implementation which created with the visual studio 2013 template (with individual users) then you will get it that way.
As developers asp.net identity stuff can be configurable according to our choice. For that you need to go deep into identity framework and understand how it works.
Most of simple yet very important configuration can be found in the IdentityConfig.cs file if you have used visual studio 2013 with update 3 or later.
identity framework version 1 comes with only with username without email address supporting UI, but things changed with the version 2.x and visual studio 2013 update 3 and 4 which included email address for both username and email.
You can change it to use username instead email as explained below.
New out of the box registration code is:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// 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.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
You can see that the Username and Email both uses model.Email.
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
Update your code as below
Register method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
UserManager.UserValidator = new UserValidator<ApplicationUser>(UserManager)
{
RequireUniqueEmail = false,
};
var user = new ApplicationUser { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// 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.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
RegisterViewModel
public class RegisterViewModel
{
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
LoginViewModel
public class LoginViewModel
{
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
Further you need to update other view models not to use email and instead use username
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
Then update all views to use UserName instead Email like below.
#model WebApplication2.Models.RegisterViewModel
#{
ViewBag.Title = "Register";
}
<h2>#ViewBag.Title.</h2>
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.UserName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
In my application I am trying to get a forgot password to work. I am trying to send an email to the user when he/she inputs his or her user name, sends them and email, they click on that link, and are brought back into the website and changes their password. Only thing is that my linq query is wrong an is not checking to see if the username exists in the database. Is this the right way to go by getting a forget password to work?
Here is my code
Controller
// GET: /Account/ForgotPassword
[AllowAnonymous]
public ActionResult ForgetPassword()
{
return View();
}
// Post: /Account/ForgotPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ForgetPassword(ForgetPasswordModel model, string UserName)
{
string emailAddress = (from i in db.UserProfiles
where i.UserName.Equals(model.Username)
select i.Email).Single();
if (!string.IsNullOrEmpty(emailAddress))
{
string confirmationToken =
WebSecurity.GeneratePasswordResetToken(model.Username);
dynamic email = new Email("ChngPasswordEmail");
email.To = emailAddress;
email.UserName = model.Username;
email.ConfirmationToken = confirmationToken;
email.Send();
return RedirectToAction("ResetPwStepTwo");
}
return RedirectToAction("InvalidUserName");
}
Model
public class ForgetPasswordModel
{
[Required]
[Display(Name = "Username")]
public string Username { get; set; }
}
View
#model MyFestival.Models.UserProfile
#{
ViewBag.Title = "Forgot Password";
}
<hr />
<div class="form-group">
<h3 class="panel-title">Did you forget your password?</h3>
</div>
#using (Html.BeginForm())
{
<div class="">
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, null, new { #style = "color:red;" })
<hr />
<label>To reset your password, input your email address and press the Reset Password button.</label>
<br/>
<div class="form-group" >
<div class="col-md-12" >
<div class="input-group">
<span class="input-group-addon" ><i class="glyphicon glyphicon-user" ></i ></span >
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control", #placeholder = "Username" })
</div >
#Html.ValidationMessageFor(m => m.UserName, null, new { #style = "color:red;" })
</div>
</div>
<br/>
<br/>
<div class="form-group" >
<div class="col-md-offset-2 col-md-10" >
<input type="submit" class="btn btn-default" value="Reset Password"/ >
#Html.ActionLink("Back to Login", "Login", null, new { #class = "btn btn-info" })
</div >
</div>
</div>
}
I've just spotted that you have both ForgetPasswordModel model and string username as arguments of your controller action and later you use Username property of your model. I assume that Model Binder just initializes the stirng username instead of ForgegPasswordModel. Could you try removing stirng username - the second parameter of ForgetPassword action?
You can create your own GUID and send it with email to user.
When user click on email link check Guid and update new password of user.
Here is the sample code
Create a view to enter forgot password email
#{
ViewBag.Title = "Forgot Password";
}
<h2>Forgot Password</h2>
#using (Html.BeginForm())
{
<div class="form-horizontal">
<hr />
<div class="text-success">
#ViewBag.Message
</div>
<div class="form-group">
Please enter your registered email address below to receive an email containing a link, to reset your password.
</div>
<div class="form-group">
<label class="control-label col-md-2">Email Address</label>
#Html.TextBox("EmailID", "", new { #class = "form-control" })
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Submit" class="btn btn-success" />
</div>
</div>
</div>
}
Then in your Controller get Email id from user, check if email exists and create new GUID, save it in database, send email to user.
[HttpPost]
public ActionResult ForgotPassword(string EmailID)
{
string resetCode = Guid.NewGuid().ToString();
var verifyUrl = "/Account/ResetPassword/" + resetCode;
var link = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery, verifyUrl);
//get user details from database.
using (var context = new LoginRegistrationInMVCEntities())
{
var getUser = (from s in context.RegisterUsers where s.Email == EmailID select s).FirstOrDefault();
if (getUser != null)
{
getUser.ResetPasswordCode = resetCode;
//This line I have added here to avoid confirm password not match issue , as we had added a confirm password property
context.Configuration.ValidateOnSaveEnabled = false;
context.SaveChanges();
var subject = "Password Reset Request";
var body = "Hi " + getUser.FirstName + ", <br/> You recently requested to reset your password for your account. Click the link below to reset it. " +
" <br/><br/><a href='" + link + "'>" + link + "</a> <br/><br/>" +
"If you did not request a password reset, please ignore this email or reply to let us know.<br/><br/> Thank you";
SendEmail(getUser.Email, body, subject);
ViewBag.Message = "Reset password link has been sent to your email id.";
}
else
{
ViewBag.Message = "User doesn't exists.";
return View();
}
}
return View();
}
private void SendEmail(string emailAddress, string body, string subject)
{
using (MailMessage mm = new MailMessage("youremail#gmail.com", emailAddress))
{
mm.Subject = subject;
mm.Body = body;
mm.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.gmail.com";
smtp.EnableSsl = true;
NetworkCredential NetworkCred = new NetworkCredential("youremail#gmail.com", "YourPassword");
smtp.UseDefaultCredentials = true;
smtp.Credentials = NetworkCred;
smtp.Port = 587;
smtp.Send(mm);
}
}
Now, when user click on the email and enter new password, check Guid with what we have saved in database and update password if guid matches.
Check for more info:
Forgot password functionality in ASP.NET MVC (Reset password by Email)