User Registration, Login, Email Notification, And Account Activation Using MVC

Introduction

In this blog, we will learn how to create a database for new registration using SQL server 2014. We will learn how to create registration page and login page using MVC and Entity framework. And also write a code for how to send email notification email after registration. How to activate email address and how to encrypt Password etc.

In this blog, I will explain the following topics,

  • Registration
  • Login
  • Email Notification
  • Email Activation
  • Encrypt password or password hashing
  • Generate email OTP
  • Change password using OTP

Using MVC and entity framework and SQL server 2014

Step 1

First I will create a database table and the table name is UserM

Step 2

Create one MVC project using Visual Studio

Step 3

After creating project create one folder inside the project and name is DBContext and Add Entitydata Model in this folder.

Step 4

Create controller inside the controller folder with name Register. and write the below code to register the data. I am using Index ActionResult method for registration purpose, you can create another method. In this, I have included two methods one IsEmailExists and another SendEmailToUser. Both methods is shown below

 // #region Registration post method for data save    
 [HttpPost]
 public ActionResult Index(UserM objUsr) {
     // email not verified on registration time    
     objUsr.EmailVerification = false;
     //check email is exist or not in db.
     var IsExists = IsEmailExists(objUsr.Email);
     if (IsExists) {
         ModelState.AddModelError("EmailExists", "This Email is already Exists Please enter other email");
         return View("Index");
     }
     //it generate unique code       
     objUsr.ActivetionCode = Guid.NewGuid();
     //password convert    
     objUsr.Password = encryptPassword.textToEncrypt(objUsr.Password);
     objCon.UserMs.Add(objUsr);
     objCon.SaveChanges();
     //region Send Email verification links
     SendEmailToUser(objUsr.Email, objUsr.ActivetionCode.ToString());
     var message = "Registration Completed. Please check your email :" + objUsr.Email;
     ViewBag.Message = message;
     //endregion
     return View("Registration");
 }
 // #endregion
 public bool IsEmailExists(string eMail) {
     var IsCheck = objCon.UserMs.Where(email => email.Email == eMail).FirstOrDefault();
     return IsCheck != null;
 }
 // #endregion
 //#region Send Email notification on registered email id
 public void SendEmailToUser(string emailId, string activationCode) {
     //var GenarateUserVerificationLink = "/Register/UserVerification/" + activationCode;          
     //var link = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery, GenarateUserVerificationLink);
     var link = "https://localhost:44329/Register/UserVerification/" + activationCode;
     var fromMail = new MailAddress("Your email id ", "R.R Reaserch and Development"); // set your email    
     var fromEmailpassword = "your email id password"; // Set your password     
     var toEmail = new MailAddress(emailId);
     var smtp = new SmtpClient();
     smtp.Host = "smtp.gmail.com";
     smtp.Port = 587;
     smtp.EnableSsl = true;
     smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
     smtp.UseDefaultCredentials = false;
     smtp.Credentials = new NetworkCredential(fromMail.Address, fromEmailpassword);
     var Message = new MailMessage(fromMail, toEmail);
     Message.Subject = "Registration Completed";
     Message.Body = "<br/> Your registration completed succesfully." + "<br/> please click on the below link for account verification" + "<br/><br/><a href=" + link + ">" + link + "</a>";
     Message.IsBodyHtml = true;
     smtp.Send(Message);
 }

Step 5

Now add View forregistration 

@model MVCProjectPractics.Models.UserRegistration

@{
    ViewBag.Title = "Index";
}
@using (Html.BeginForm("Index","Register",FormMethod.Post))
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h3 style="text-align:center">User Registration</h3>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @*@Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })*@
            <span class="control-label col-md-2"><b>First Name:</b></span>
            <div class="col-md-10">
                @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @*@Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })*@
            <span class="control-label col-md-2"><b>Last Name:</b></span>
            <div class="col-md-10">
                @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <span class="control-label col-md-2"><b>Email:</b></span>
            <div class="col-md-10">
                @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
                @Html.ValidationMessage("EmailExists", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @*@Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })*@
            <span class="control-label col-md-2"><b>Password:</b></span>
            <div class="col-md-10">
                @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @*@Html.LabelFor(model => model.ConfirmPassword, htmlAttributes: new { @class = "control-label col-md-2" })*@
            <span class="control-label col-md-2"><b>Confirm Password:</b></span>
            <div class="col-md-10">
                @Html.EditorFor(model => model.ConfirmPassword, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ConfirmPassword, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Register" class="btn btn-success" />
                <input type="submit" value="Register" class="btn btn-danger" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> 

Now run this project and output look like below

After providing the details and click on the register button please check your email id.

After Registration check the database it will display like below result.

result

Step 6

Now create Login Action inside the controller

public ActionResult Login() {
        return View();
    }
    [HttpPost]
public ActionResult Login(UserLogin LgnUsr) {
    var _passWord = encryptPassword.textToEncrypt(LgnUsr.Password);
    bool Isvalid = objCon.UserMs.Any(x => x.Email == LgnUsr.EmailId && x.EmailVerification == true && x.Password == _passWord);
    if (Isvalid) {
        int timeout = LgnUsr.Rememberme ? 60 : 5; // Timeout in minutes, 60 = 1 hour.    
        var ticket = new FormsAuthenticationTicket(LgnUsr.EmailId, false, timeout);
        string encrypted = FormsAuthentication.Encrypt(ticket);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
        cookie.Expires = System.DateTime.Now.AddMinutes(timeout);
        cookie.HttpOnly = true;
        Response.Cookies.Add(cookie);
        return RedirectToAction("Index", "UserDash");
    } else {
        ModelState.AddModelError("", "Invalid Information... Please try again!");
    }
    return View();
}

Login View

@model MVCProjectPractics.Models.UserLogin

@{
    ViewBag.Title = "Login";
}
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h3 style="text-align:center">User Login</h3>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.EmailId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.EmailId, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.EmailId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Rememberme, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                <div class="checkbox">
                    @Html.EditorFor(model => model.Rememberme)
                    @Html.ValidationMessageFor(model => model.Rememberme, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Login" class="btn btn-primary" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Registration", "Index") ||
    @Html.ActionLink("Reset Passward", "ForgetPassword")
</div>

Login Output

Step 7

Now write the below code for Reset Password with email OTP 

// startregion Change password details
public ActionResult ForgetPassword() {
          return View();
      }
      [HttpPost]
  public ActionResult ForgetPassword(ForgetPassword pass) {
      var IsExists = IsEmailExists(pass.EmailId);
      if (!IsExists) {
          ModelState.AddModelError("EmailNotExists", "This email is not exists");
          return View();
      }
      var objUsr = objCon.UserMs.Where(x => x.Email == pass.EmailId).FirstOrDefault();
      // Genrate OTP     
      string OTP = GeneratePassword();
      objUsr.ActivetionCode = Guid.NewGuid();
      objUsr.OTP = OTP;
      objCon.Entry(objUsr).State = System.Data.Entity.EntityState.Modified;
      objCon.SaveChanges();
      ForgetPasswordEmailToUser(objUsr.Email, objUsr.ActivetionCode.ToString(), objUsr.OTP);
      ViewBag.Message = "Password reset links has been sent on your email id please check email and click on link";
      return RedirectToAction("ForgetPassword", "UserDash");
  }
  public void ForgetPasswordEmailToUser(string emailId, string activationCode, string OTP) {
      //var GenarateUserVerificationLink = "/Register/UserVerification/" + activationCode;          
      //var link = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery, GenarateUserVerificationLink);
      var link = "https://localhost:44329/Register/ChangePassword/" + activationCode;
      var fromMail = new MailAddress("youremail id", "R.R Reaserch and Development"); // set your email    
      var fromEmailpassword = "your password"; // Set your password     
      var toEmail = new MailAddress(emailId);
      var smtp = new SmtpClient();
      smtp.Host = "smtp.gmail.com";
      smtp.Port = 587;
      smtp.EnableSsl = true;
      smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
      smtp.UseDefaultCredentials = false;
      smtp.Credentials = new NetworkCredential(fromMail.Address, fromEmailpassword);
      var Message = new MailMessage(fromMail, toEmail);
      Message.Subject = "Registration Completed-Demo";
      Message.Body = "<br/> please click on the below link for change the password" + "<br/><br/><a href=" + link + ">" + link + "</a>" + "<br> OPT for password change:" + OTP;
      Message.IsBodyHtml = true;
      smtp.Send(Message);
  }
  public string GeneratePassword() {
      string OTPLength = "4";
      string OTP = string.Empty;
      string Chars = string.Empty;
      Chars = "1,2,3,4,5,6,7,8,9,0";
      char[] seplitChar = {
          ','
      };
      string[] arr = Chars.Split(seplitChar);
      string NewOTP = "";
      string temp = "";
      Random rand = new Random();
      for (int i = 0; i < Convert.ToInt32(OTPLength); i++) {
          temp = arr[rand.Next(0, arr.Length)];
          NewOTP += temp;
          OTP = NewOTP;
      }
      return OTP;
  }
//change password

Step 8

Create View for forget password

@model MVCProjectPractics.Models.ForgetPassword

@{
    ViewBag.Title = "ForgetPassword";
}

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h3 style="text-align:center">Forget Password</h3>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.EmailId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.EmailId, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.EmailId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Reset Password" class="btn btn-primary" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Step 9

Please check email for forget the password link and OTP

Step 10

Write the method for changing the password using the received OTP inside the Register controller

//change password
public ActionResult ChangePassword() {
          return View();
      }
      [HttpPost]
public ActionResult ChangePassword(ChangePassword changePass, UserM objUsr) {
      string password = changePass.Password;
      objUsr = objCon.UserMs.Where(x => x.OTP == changePass.OTP).FirstOrDefault();
      objUsr.Password = encryptPassword.textToEncrypt(password);
      objCon.Entry(objUsr).State = System.Data.Entity.EntityState.Modified;
      objCon.SaveChanges();
      ViewBag.Message = "Password has been change successfully..!";
      return RedirectToAction("PasswordChange", "UserDash");
 }
//Endregion

Step 11

Create View to Change the password,

@model MVCProjectPractics.Models.ChangePassword

@{
    ViewBag.Title = "ChangePassword";
}

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h3 style="text-align:center">Change Password</h3>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.OTP, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.OTP, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.OTP, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ConfirmPassword, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ConfirmPassword, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ConfirmPassword, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Change Password" class="btn btn-primary" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Login", "Login")
</div>

All Models Code is below,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Data.SqlClient;
namespace MVCProjectPractics.Models {
    [Table("UserM")]
    public class ChangePassword {
        [Key]
        public int UserId {
            get;
            set;
        }
        [Required(AllowEmptyStrings = false, ErrorMessage = "OTP is requierd")]
        public string OTP {
            get;
            set;
        }
        [Required(AllowEmptyStrings = false, ErrorMessage = "Password is requierd")]
        [DataType(DataType.Password)]
        [MinLength(6, ErrorMessage = "Need min 6 char")]
        public string Password {
            get;
            set;
        }
        [Required(AllowEmptyStrings = false, ErrorMessage = "Confirm Password is requierd")]
        [DataType(DataType.Password)]
        [Compare("Password", ErrorMessage = "Confirm Password should match with Password")]
        public string ConfirmPassword {
            get;
            set;
        }
    }
}

User Registration

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MVCProjectPractics.Models {
    [Table("[UserM]")]
    public class UserRegistration {
        [Key]
        public int UserId {
            get;
            set;
        }
        [Required(AllowEmptyStrings = false, ErrorMessage = "First Name is requierd")]
        public string FirstName {
            get;
            set;
        }
        [Required(AllowEmptyStrings = false, ErrorMessage = "Last Name is requierd")]
        public string LastName {
            get;
            set;
        }
        [Required(AllowEmptyStrings = false, ErrorMessage = "Email ID is requierd")]
        public string Email {
            get;
            set;
        }
        [Required(AllowEmptyStrings = false, ErrorMessage = "Password is requierd")]
        [DataType(DataType.Password)]
        [MinLength(6, ErrorMessage = "Need min 6 character")]
        public string Password {
            get;
            set;
        }
        [Required(AllowEmptyStrings = false, ErrorMessage = "Confirm Password is requierd")]
        [DataType(DataType.Password)]
        [Compare("Password", ErrorMessage = "Confirm Password should match with Password")]
        public string ConfirmPassword {
            get;
            set;
        }
    }
}

Password Encrypted

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace MVCProjectPractics.Models {
    public class encryptPassword {
        public static string textToEncrypt(string paasWord) {
            return Convert.ToBase64String(System.Security.Cryptography.SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(paasWord)));
        }
    }
}

Forget Password

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Data.SqlClient;
using System.ComponentModel.DataAnnotations.Schema;
namespace MVCProjectPractics.Models {
    [Table("[UserM]")]
    public class ForgetPassword {
        [Key]
        public int UserId {
            get;
            set;
        }
        [Display(Name = "User Email ID")]
        [Required(AllowEmptyStrings = false, ErrorMessage = "User Email Id Required")]
        public string EmailId {
            get;
            set;
        }
    }
}

User Login

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MVCProjectPractics.Models {
    [Table("[UserM]")]
    public class UserLogin {
        [Key]
        public int UserId {
            get;
            set;
        }
        [Display(Name = "User Email ID")]
        [Required(AllowEmptyStrings = false, ErrorMessage = "User Email Id Required")]
        public string EmailId {
            get;
            set;
        }
        [Display(Name = "Password")]
        [DataType(DataType.Password)]
        [Required(AllowEmptyStrings = false, ErrorMessage = "Password Required")]
        public string Password {
            get;
            set;
        }
        [Display(Name = "Remember Me")]
        public bool Rememberme {
            get;
            set;
        }
    }
}