Introduction
Whenever we develop a web application three things are common there - Sign up, Sign in, and Log out. As part of this article, we are going to discuss the following things in detail.
- How to Sign up a new user into our application
- Implementing the User Login page.
- How to use the built-in Authorize Attribute
- Implementing the logout functionality
- How to use Forms Authentication in MVC application to achieve all the above points
I will discuss MVC application security in upcoming articles. Forms Authentication is available in System.Web.Security namespace. In order to implement the Forms Authentication in MVC application, we need to do the following three things.
- Set the Authentication mode as Forms in the web.config file
- We need to use FormsAuthentication.SetAuthCookie for login
- Again we need to use FormAuthentication.SignOut for logout
Step 1
Open your favorite SQL Server database with any version. It really doesn’t matter what version it is. I am using SQL Server 2017 for this article.
Create EMPLOYEE TABLE
- CREATE TABLE [dbo].[Employee](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [Name] [nvarchar](50) NULL,
- [Gender] [char](10) NULL,
- [Age] [int] NULL,
- [Position] [nvarchar](50) NULL,
- [Office] [nvarchar](50) NULL,
- [HireDate] [datetime] NULL,
- [Salary] [int] NULL,
- [DepartmentId] [int] NULL,
- PRIMARY KEY CLUSTERED
- (
- [Id] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
- GO
-
- ALTER TABLE [dbo].[Employee] WITH CHECK ADD FOREIGN KEY([DepartmentId])
- REFERENCES [dbo].[Department] ([Id])
- GO
Create Department Table
- CREATE TABLE [dbo].[Department](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [DepartmentName] [nvarchar](50) NULL,
- PRIMARY KEY CLUSTERED
- (
- [Id] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
- GO
Create Users Table
- CREATE TABLE [dbo].[Users](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [Username] [nvarchar](50) NULL,
- [Password] [nvarchar](50) NULL,
- PRIMARY KEY CLUSTERED
- (
- [Id] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
- GO
Create Roles Table
- CREATE TABLE [dbo].[Roles](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [RoleName] [nvarchar](50) NULL,
- PRIMARY KEY CLUSTERED
- (
- [Id] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
- GO
Create UserRolsMapping Table
- CREATE TABLE [dbo].[UserRolesMapping](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [UserId] [int] NULL,
- [RoleId] [int] NULL,
- PRIMARY KEY CLUSTERED
- (
- [Id] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
- GO
-
- ALTER TABLE [dbo].[UserRolesMapping] WITH CHECK ADD FOREIGN KEY([RoleId])
- REFERENCES [dbo].[Roles] ([Id])
- GO
-
- ALTER TABLE [dbo].[UserRolesMapping] WITH CHECK ADD FOREIGN KEY([RoleId])
- REFERENCES [dbo].[Roles] ([Id])
- GO
-
- ALTER TABLE [dbo].[UserRolesMapping] WITH CHECK ADD FOREIGN KEY([UserId])
- REFERENCES [dbo].[Users] ([Id])
- GO
Step-2
Open Visual Studio 2019 or an editor of your choice and create a new project.
Step 3
Choose the "web application" project and give an appropriate name to your project. Click on "Create".
Step 4
Select the "empty" template, check on MVC checkbox and click Create.
Step 5
Right-click the Models folder and add a database model. Add Entity Framework now. For that, right-click on Models folder, select Add, then select "New Item".
You will get a window; from there, select Data from the left panel and choose ADO.NET Entity Data Model, give it the name EmployeeModel (this name is not mandatory, you can give any name) and click "Add".
After you click on "Add a window", the wizard will open. Choose EF Designer from the database and click "Next".
After clicking on "Next", a window will appear. Choose "New Connection". Another window will appear. Add your server name - if it is local, then enter a dot (.). Choose your database and click "OK".
The connection will be added. If you wish, save the connection name as you want. You can change the name of your connection below. It will save the connection in the web config. Now, click "Next".
After clicking on NEXT, another window will appear. Choose the database table name as shown in the below screenshot and click "Finish".
Entity Framework gets added and the respective class gets generated under the Models folder.
Step 6
Right-click on Controllers folder and add a controller.
A window will appear. Choose MVC5 Controller-Empty and click "Add".
After clicking on "Add", another window will appear with DefaultController. Change the name to HomeController and click "Add". The HomeController will be added under the Controllers folder. Don’t change the Controller suffix for all controllers, change only the highlight, and instead of Default, just change Home
Step 7
Right-click on the Index method in HomeController; the "Add View" window will appear with the default index name checked (use a Layout page). Click on "Add".
Complete code for HomeController
- using MvcFormAuthentication_Demo.Models;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
- using System.Web.Security;
-
- namespace MvcFormAuthentication_Demo.Controllers
- {
-
- public class HomeController : Controller
- {
- private readonly EmployeeContext _dbContext = new EmployeeContext();
- public ActionResult Index()
- {
- return View();
- }
- public ActionResult Login()
- {
- return View();
- }
- [HttpPost]
- [ValidateAntiForgeryToken]
- public ActionResult Login(UserModel user)
- {
- if (ModelState.IsValid)
- {
- bool IsValidUser = _dbContext.Users
- .Any(u => u.Username.ToLower() == user
- .Username.ToLower() && user
- .Password == user.Password);
-
- if (IsValidUser)
- {
- FormsAuthentication.SetAuthCookie(user.Username, false);
- return RedirectToAction("Index", "Employee");
- }
- }
- ModelState.AddModelError("", "invalid Username or Password");
- return View();
- }
- public ActionResult Register()
- {
- return View();
- }
- [HttpPost]
- [ValidateAntiForgeryToken]
- public ActionResult Register(User registerUser)
- {
- if (ModelState.IsValid)
- {
- _dbContext.Users.Add(registerUser);
- _dbContext.SaveChanges();
- return RedirectToAction("Login");
-
- }
- return View();
- }
- public ActionResult Logout()
- {
- FormsAuthentication.SignOut();
- return RedirectToAction("Login");
- }
- }
- }
Add two views, one for registering and a second for login
Register View Code
- @model MvcFormAuthentication_Demo.Models.User
- @{
- ViewBag.Title = "Register";
- }
-
- @using (Html.BeginForm())
- {
- @Html.AntiForgeryToken()
- <div class="card custom-card">
- <div class="card-header bg-primary text-white">
- <h3>Register Form</h3>
- </div>
- <div class="card-body">
- <div class="form-group">
- @Html.LabelFor(m => m.Username)
- @Html.TextBoxFor(m => m.Username, new { @class = "form-control" })
- @Html.ValidationMessageFor(m => m.Username)
- </div>
- <div class="form-group">
- @Html.LabelFor(m => m.Password)
- @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
- @Html.ValidationMessageFor(m => m.Password)
- </div>
- <div class="form-group">
- <button type="submit" class="btn btn-primary rounded-0">Register</button>
- @Html.ActionLink("Login here", "Login")
- </div>
-
- </div>
- </div>
- }
Login View code
- @model MvcFormAuthentication_Demo.Models.UserModel
- @{
- ViewBag.Title = "Login";
- }
-
- @using (Html.BeginForm())
- {
- @Html.AntiForgeryToken()
- <div class="card custom-card">
- <div class="card-header bg-primary text-white">
- <h3>Login Form</h3>
- </div>
- <div class="card-body">
- <div class="form-group">
- @Html.LabelFor(m=>m.Username)
- @Html.TextBoxFor(m => m.Username, new { @class = "form-control" })
- @Html.ValidationMessageFor(m => m.Username)
- </div>
- <div class="form-group">
- @Html.LabelFor(m => m.Password)
- @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
- @Html.ValidationMessageFor(m => m.Password)
- </div>
- <div class="form-group">
- <button type="submit" class="btn btn-primary rounded-0">Login</button>
- @Html.ActionLink("New User","Register")
- </div>
-
- </div>
- </div>
- }
Step 8
Open web.config and Add following code for forms authentication
- <authentication mode="Forms">
- <forms loginUrl="Home/Login"></forms>
- </authentication>
Step 9
Similarly, add another controller for CRUD operation. Right-click on the Controllers folder and add a controller.
A window will appear. Choose MVC5 Controller with a view, using Entity Framework and click "Add".
After clicking on "Add", another window will appear. Choose a model class and database context class, click on Add. It will generate the respective view with the controller - create, edit, update, and delete code and views.
Use Authorize Attribute
- [Authorize]
- public class EmployeesController : Controller
- {
- }
The Authorize Attribute is the built-in attribute provided by MVC which is basically used to authenticate a user. Decorate the action methods which you don’t want any anonymous user to access with Authorize Attribute.
Step 10
Open _Layout file and modify it with the following code.
- <nav class="navbar navbar-expand-lg navbar-light bg-light">
- <a class="navbar-brand" href="#">
- @Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
- </a>
- <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
- <span class="navbar-toggler-icon"></span>
- </button>
- <div class="collapse navbar-collapse" id="collapsibleNavbar">
- <ul class="navbar-nav">
- @if (User.Identity.IsAuthenticated)
- {
- <li>@Html.ActionLink("Employee List", "Index", "Employees", new { @class = "nav-link" })</li>
- <li>@Html.ActionLink("Add New Employee", "Create", "Employees", new { @class = "nav-link" })</li>
- <li class="nav-item dropdown">
- <a class="nav-link dropdown-toggle text-center text-uppercase" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
- @User.Identity.Name
- </a>
- <div class="dropdown-menu" aria-labelledby="navbarDropdown">
- <a class="dropdown-item" href="#">My Account</a>
- <a class="dropdown-item" href="#">Edit Profile</a>
- <div class="dropdown-divider"></div>
- @Html.ActionLink("Logout", "Logout", "Home", new { @class = "nav-link text-center text-uppercase" })
- </div>
- </li>
- }
- else
- {
- <li>@Html.ActionLink("Home", "Index", "Home", new { @class = "nav-link" })</li>
- <li>@Html.ActionLink("About", "About", "Home", new { @class = "nav-link" })</li>
- <li>@Html.ActionLink("Register", "Register", "Home", new { @class = "nav-link float-left" })</li>
- <li>@Html.ActionLink("Login", "Login", "Home", new { @class = "nav-link float-left" })</li>
-
- }
- </ul>
- </div>
- </nav>
Step 11
Build and run your application ctrl+F5
Output Screens
Register Form
Login Form
Employee List
Add New Employee
Edit Employee
Employee Details
Delete Employee