Part 3 - How to implement custom Forms Authentication in ASP.NET MVC4 application




Introduction

In this post, I am going to implement custom Role Provider in Forms authentication in ASP.NET MVC4 application.
  • In the First part of this series I have implemented very simple and easy authentication.
  • In the Second part of this series I have implemented our custom membership provider to take full control of the database and forms authentication mechanism (like validate user, create user, update user, delete user, change password and more).
  • Now in this part (Part 3) I would like to implement a custom role provider.
  • and In the next part (part 4) We will implement a custom user principal and identity
There might be multiple types of users (Like Administrator, registered users, Agent users) in an application, who can perform different type of action based on the roles assigned to a user. For this authorization process ASP.NET offers a RoleProvider class. The class includes method to create and delete roles, to add and remove users in a role, and tell whether a user belongs to a particular role.
Here we will implement our custom role provider that will be used to return the roles that a user has to take full control of the database and authorization process mechanism.

Step-1 : Create 2 tables.

Open Database > Right Click on Table > Add New Table > Add Columns > Save > Enter table name > Ok.

Table Name : Roles



Table Name : UserRoles


Step-2: update Entity Data Model.

Go to Solution Explorer > Open Model (created in the part 1) > Right click on empty area (inside model) > Update model from Database > Add Tables > Finish.

Step-3 : Add a class for extends RoleProvider class.

Go to solution explorer > Right click on the project name > Add > Class > Enter class name > Add
Here we will extend RoleProvider class.

Step-4 : Override two method "GetRolesForUser" and "IsUserInRole" of RoleProvider class.

Complete Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
using System.Web.Security;

namespace MvcAuthentication
{
    public class MyRoleProvider : RoleProvider
    {
        private int _cacheTimeoutInMinute = 20;
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        public override string ApplicationName
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public override void CreateRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            throw new NotImplementedException();
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            throw new NotImplementedException();
        }

        public override string[] GetAllRoles()
        {
            throw new NotImplementedException();
        }

        public override string[] GetRolesForUser(string username)
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                return null;
            }

            //check cache
            var cacheKey = string.Format("{0}_role", username);
            if (HttpRuntime.Cache[cacheKey] != null)
            {
                return (string[])HttpRuntime.Cache[cacheKey];
            }
            string[] roles = new string[]{};
            using (MyDatabaseEntities dc = new MyDatabaseEntities())
            {
                roles = (from a in dc.Roles
                             join b in dc.UserRoles on a.RoleID equals b.RoleID
                             join c in dc.Users on b.UserID equals c.UserID
                             where c.Username.Equals(username)
                             select a.ROleName).ToArray<string>();
                if (roles.Count() > 0)
                {
                    HttpRuntime.Cache.Insert(cacheKey, roles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinute), Cache.NoSlidingExpiration);

                }
            }
            return roles;
        }

        public override string[] GetUsersInRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            var userRoles = GetRolesForUser(username);
            return userRoles.Contains(roleName);
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        public override bool RoleExists(string roleName)
        {
            throw new NotImplementedException();
        }
    }
}
        

Step-5: Edit web.config for Enable our custom role provider.

In this example, I have written the following configuration in the web.config file for Enable our custom role provider
 
    <roleManager defaultProvider="MyRoleProvider" enabled="true">
      <providers>
        <add name="MyRoleProvider" type="MvcAuthentication.MyRoleProvider, MvcAuthentication"/>
      </providers>
    </roleManager>
        

Step-6: Add new action into your controller (here in HomeController) for "Admin" role user

Here I have used "AdminIndex" Action. Please write this following code
[Authorize(Roles="Admin")]
public ActionResult AdminIndex()
{
    return View();
}
        

Step-7: Add view for the Action (here in "AdminIndex") & design.

Right Click on Action Method (here right click on "AdminIndex" action) > Add View... > Enter View Name > Select View Engine (Razor) > Add.
@{
    ViewBag.Title = "AdminIndex";
}

<h2>Admin Index</h2>
<div>Welcome @(Request.IsAuthenticated? HttpContext.Current.User.Identity.Name : "") (Admin)</div>
        

Step-8: Add new action into your controller (here in HomeController) for "User" role user

Here I have used "UserIndex" Action. Please write this following code
[Authorize(Roles="User")]
public ActionResult UserIndex()
{
    return View();
}
        

Step-9: Add view for the Action (here in "UserIndex") & design.

Right Click on Action Method (here right click on "UserIndex" action) > Add View... > Enter View Name > Select View Engine (Razor) > Add.
@{
    ViewBag.Title = "UserIndex";
}

<h2>User Index</h2>
<div>Welcome @(Request.IsAuthenticated? HttpContext.Current.User.Identity.Name : "")  (User) </div>


        

Step-10: Run Application.


Hello ! My name is Sourav Mondal. I am a software developer working in Microsoft .NET technologies since 2010.

I like to share my working experience, research and knowledge through my site.

I love developing applications in Microsoft Technologies including Asp.Net webforms, mvc, winforms, c#.net, sql server, entity framework, Ajax, Jquery, web api, web service and more.