In this article I will explain with an example, how to implement Role based Security in ASP.Net MVC Razor.
User Login Authentication and Roles based Security will be implemented using Custom Forms Authentication in ASP.Net MVC Razor.
 
 
Database
I am making use of the database tables.
Users
Implement Role based Security in ASP.Net MVC
 
Roles
Implement Role based Security in ASP.Net MVC
 
The Roles table has two Roles i.e. Administrator and User.
Implement Role based Security in ASP.Net MVC
 
Note: You can download the database table SQL by clicking the download link below.
          Download SQL file
 
 
Stored Procedure to Validate the User Credentials
The following stored procedure is used to validate the user credentials, this stored procedure first checks whether the username and password are correct else returns -1.
If the username and password are correct but the user has not been activated then the code returned is -2.
If the username and password are correct and the user account has been activated then UserId and the Role is returned by the stored procedure.
CREATE PROCEDURE [dbo].[Validate_User]
      @Username NVARCHAR(20),
      @Password NVARCHAR(20)
AS
BEGIN
      SET NOCOUNT ON;
      DECLARE @UserId INT, @LastLoginDate DATETIME, @RoleId INT
     
      SELECT @UserId = UserId, @LastLoginDate = LastLoginDate, @RoleId = RoleId
      FROM Users WHERE Username = @Username AND [Password] = @Password
     
      IF @UserId IS NOT NULL
      BEGIN
            IF NOT EXISTS(SELECT UserId FROM UserActivation WHERE UserId = @UserId)
            BEGIN
                  UPDATE Users
                  SET LastLoginDate = GETDATE()
                  WHERE UserId = @UserId
                 
                  SELECT @UserId [UserId],
                              (SELECT RoleName FROM Roles
                               WHERE RoleId = @RoleId) [Roles] -- User Valid
            END
            ELSE
            BEGIN
                  SELECT -2 [UserId], '' [Roles]-- User not activated.
            END
      END
      ELSE
      BEGIN
            SELECT -1 [UserId], '' [Roles] -- User invalid.
      END
END
 
 
Entity Framework Data Model
Once the Entity Framework is configured and connected to the database table, the Model will look as shown below.
Note: The Entity Framework has been already configured in the User Registration article and hence we will continue with further step i.e. adding the Roles Table and adding the Stored Procedure (discussed earlier) to the existing Entity Framework Data Model.
To add the Roles Table and the Stored Procedure, open the User Data Model and then right click on the User Table and click on the Update Model from Database option from the Context menu.
 
Implement Role based Security in ASP.Net MVC
 
 
Function Import: Importing the Stored Procedure as Function
In order to import the Stored Procedure as Function, right click on the User Table and click on Add New option and then Function Import option from the Context menu.
Implement Role based Security in ASP.Net MVC
 
The above action will open the Add Function Import Dialog window. Here you will need to
1. Function Import Name: Specify the name of the method which will be used to execute the Stored Procedure.
2. Stored Procedure / Function Name: Select the Stored Procedure / Function to be imported.
3. Returns a Collection Of: The Stored Procedure used in this article returns multiple values and hence the Complex option is selected.
Finally once all the above is done, simply click the OK button.
Implement Role based Security in ASP.Net MVC
 
 
Model
The Model class User.cs remains the same as the User Registration article except few changes i.e. a new property RememberMe has been added and properties of Role tables are added.
namespace Role_Menu_MVC
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
 
    public partial class User
    {
        public int UserId { get; set; }
 
        [Required(ErrorMessage = "Required.")]
        public string Username { get; set; }
 
        [Required(ErrorMessage = "Required.")]
        public string Password { get; set; }
 
        [Required(ErrorMessage = "Required.")]
        [Compare("Password", ErrorMessage = "Passwords do not match.")]
        public string ConfirmPassword { get; set; }
 
        [Required(ErrorMessage = "Required.")]
        [EmailAddress(ErrorMessage = "Invalid email address.")]
        public string Email { get; set; }
 
        public System.DateTime CreatedDate { get; set; }
 
        public Nullable<System.DateTime> LastLoginDate { get; set; }
        public Nullable<int> RoleId { get; set; }
 
        public virtual Role Role { get; set; }
 
        public bool RememberMe { get; set; }
    }
}
 
 
 
Namespaces
You will need to import the following namespace.
using System.Web.Security;
using System.Security.Principal;
 
 
Controller
The Controller consists of four Action methods.
Action method for handling GET operation for Login
Inside this Action method, simply the View is returned. This Action method is decorated with AllowAnonymous Data Annotation which signifies Form Based authentication that this method can be accessed without authentication.
 
Action method for handling GET operation for Profile
Inside this Action method, simply the View is returned. This Action method is decorated with Authorize Data Annotation which signifies Form Based authentication that this method requires authentication to be accessed.
 
Action method for handling POST operation for Login
Inside this Action method, the ValidateUser method is called which executes the Stored Procedure that values the User’s credentials.
The ValidateUser method returns the Complex object RoleUser which consists of two properties UserId and Roles.
The UserId returned from the Stored Procedure is captured and if the value is not -1 (Username or password incorrect) or -2 (Account not activated) then the user is redirected to the either Profile View or the View present in ReturnUrl QueryString parameter after setting the Forms Authentication Cookie with the Role.
For the status -1 and -2, the message is displayed to the user using ViewBag object.
 
Action method for handling POST operation for Logout
Inside this Action method, the SignOut method of Forms Authentication is called which clears the Forms Authentication Cookie and the user is redirected to the Index View.
public class HomeController : Controller
{
    [AllowAnonymous]
    public ActionResult Index()
    {
        return View();
    }
 
    [Authorize]
    public ActionResult Profile()
    {
        return View();
    }
 
    [HttpPost]
    [AllowAnonymous]
    public ActionResult Index(User user)
    {
        UsersEntities usersEntities = new UsersEntities();
        RoleUser roleUser = usersEntities.ValidateUser(user.Username, user.Password).FirstOrDefault();
 
        string message = string.Empty;
        switch (roleUser.UserId.Value)
        {
            case -1:
                message = "Username and/or password is incorrect.";
                break;
            case -2:
                message = "Account has not been activated.";
                break;
            default:
                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user.Username, DateTime.Now, DateTime.Now.AddMinutes(2880), user.RememberMe, roleUser.Roles, FormsAuthentication.FormsCookiePath);
                string hash = FormsAuthentication.Encrypt(ticket);
                HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
 
                if (ticket.IsPersistent)
                {
                    cookie.Expires = ticket.Expiration;
                }
                Response.Cookies.Add(cookie);
                if (!string.IsNullOrEmpty(Request.Form["ReturnUrl"]))
                {
                    return RedirectToAction(Request.Form["ReturnUrl"].Split('/')[2]);
                }
                else
                {
                    return RedirectToAction("Profile");
                }
        }
 
        ViewBag.Message = message;
        return View(user);
    }
 
    [HttpPost]
    [Authorize]
    public ActionResult Logout()
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Index");
    }
}
 
 
Setting Roles in Global.asax
Inside Application_AuthenticateRequest event of the Global.asax file, the Roles are fetched from the FormsAuthentication Ticket and assigned to the HttpContext User object. This way the Role is available throughout the Application through the Context.
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    if (HttpContext.Current.User != null)
    {
        if (HttpContext.Current.User.Identity.IsAuthenticated)
        {
            if (HttpContext.Current.User.Identity is FormsIdentity)
            {
                FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
                FormsAuthenticationTicket ticket = id.Ticket;
                string userData = ticket.UserData;
                string[] roles = userData.Split(',');
                HttpContext.Current.User = new GenericPrincipal(id, roles);
            }
        }
    }
}
 
 
Views
Index
Inside the View, in the very first line the User Model class is declared as Model for the View.
The View consists of an HTML Form which has been created using the Html.BeginForm method with the following parameters.
ActionName – Name of the Action. In this case the name is Index.
ControllerName – Name of the Controller. In this case the name is Home.
FormMethod – It specifies the Form Method i.e. GET or POST. In this case it will be set to POST.
Inside the View, the following four HTML Helper functions are used:-
1. Html.TextBoxFor – Creating a TextBox for the Model property.
2. Html.PasswordFor – Creating a Password TextBox for the Model property.
3. Html.ValidationMessageFor – Displaying the Validation message for the property.
4. Html.CheckBoxFor – Creating a CheckBox for the Model property.
There is a Submit button which when clicked, the Form gets submitted. There is also a Hidden Field which is used to save the value of the ReturnUrl QueryString parameter.
The jQuery and the jQuery Validation script bundles are rendered at the end of the Model using the Scripts.Render function.
ViewBag’s Message object is checked for NULL and if it is not NULL then the string message is displayed using JavaScript Alert Message Box.
@model Role_Menu_MVC.User
 
@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width"/>
    <title>Index</title>
    <style type="text/css">
        body {
            font-family: Arial;
            font-size: 10pt;
        }
 
        table {
            border: 1px solid #ccc;
            border-collapse: collapse;
        }
 
        table th {
            background-color: #F7F7F7;
            color: #333;
            font-weight: bold;
        }
 
        table th, table td {
            padding: 5px;
            border: 1px solid #ccc;
        }
 
        .error {
            color: red;
        }
    </style>
</head>
<body>
    @using (Html.BeginForm("Index", "Home", FormMethod.Post))
    {
        <table border="0" cellpadding="0" cellspacing="0">
            <tr>
                <th colspan="3">
                    Login
                </th>
            </tr>
            <tr>
                <td>
                    Username
                </td>
                <td>
                    @Html.TextBoxFor(m => m.Username)
                </td>
                <td>
                    @Html.ValidationMessageFor(m => m.Username, "", new { @class = "error" })
                </td>
            </tr>
            <tr>
                <td>
                    Password
                </td>
                <td>
                    @Html.PasswordFor(m => m.Password)
                </td>
                <td>
                    @Html.ValidationMessageFor(m => m.Password, "", new { @class = "error" })
                </td>
            </tr>
            <tr>
                <td>
                    Remember Me
                </td>
                <td>
                    @Html.CheckBoxFor(m => m.RememberMe)
                </td>
                <td>
                   
                </td>
            </tr>
            <tr>
                <td><input type = "hidden" name = "ReturnUrl" value="@Request.QueryString["ReturnUrl"]" /></td>
                <td>
                    <input type="submit" value="Submit"/>
                </td>
                <td></td>
            </tr>
        </table>
    }
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/jqueryval")
    @if (@ViewBag.Message != null)
    {
        <script type="text/javascript">
            $(function () {
                alert("@ViewBag.Message")
            });
        </script>
    }
</body>
</html>
 
Profile
The Profile View displays the name of the Current Logged in User and it also consists of an HTML Form with an HTML Anchor link for Logout functionality.
When the Logout link is clicked, the Form gets submitted and the Logout Action method gets called.
The Profile page consists of a Bootstrap Responsive Menu and the Services menu item is only available for Users who are in Administrators role. This is implemented with the help of Users.IsInRole method of the HttpContext User object.
@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width"/>
    <title>Profile</title>
</head>
<body>
    <link rel="stylesheet" href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css'
          media="screen"/>
    <div class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
                        aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">ASPSnippets</a>
            </div>
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <div id="Menu1">
                    <ul class="nav navbar-nav">
                        <li><a class="selected" href="#">Home</a></li>
                        @if (User.IsInRole("Administrator"))
                        {
                            <li>
                                <a class="popout" href="#">Services</a><ul class="level2 dropdown-menu">
                                    <li><a class="" href="#">Consulting</a></li>
                                    <li><a class="" href="#">Outsourcing</a></li>
                                </ul>
                            </li>
                        }
                        <li><a href="#">About</a></li>
                        <li><a href="#">Contact</a></li>
                        <li><a href="#" onclick="document.forms[0].submit();">Logout</a></li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
    <div style="margin-left:10pt">
        Welcome
        <b>@HttpContext.Current.User.Identity.Name</b>
        <br/>
        <br/>
        @using (Html.BeginForm("Logout", "Home", FormMethod.Post))
        {
           
        }
    </div>
    <script type="text/javascript" src='https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js'></script>
    <script type="text/javascript" src='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js'></script>
    <script type="text/javascript">
        $(function () {
            //Remove the style attributes.
            $(".navbar-nav li, .navbar-nav a, .navbar-nav ul").removeAttr('style');
 
            //Apply the Bootstrap class to the Submenu.
            $(".dropdown-menu").closest("li").removeClass().addClass("dropdown-toggle");
 
            //Apply the Bootstrap properties to the Submenu.
            $(".dropdown-toggle").find("a").eq(0).attr("data-toggle", "dropdown").attr("aria-haspopup", "true").attr("aria-expanded", "false").append("<span class='caret'></span>");
 
            //Apply the Bootstrap "active" class to the selected Menu item.
            $("a.selected").closest("li").addClass("active");
            $("a.selected").closest(".dropdown-toggle").addClass("active");
        });
    </script>
</body>
</html>
 
 
Web.Config Configuration
You will need to add the following configuration in the Web.Config file in the <system.web> section.
 <authentication mode="Forms">
      <forms defaultUrl="/Home/Profile" loginUrl="/Home/Index" slidingExpiration="true" timeout="2880"></forms>
</authentication>
 
 
Screenshots
Desktop display
Implement Role based Security in ASP.Net MVC
 
Mobile display
Implement Role based Security in ASP.Net MVC
 
 
Downloads