This article explains about the implementation of custom authorization with the user roles using ASP.NET MVC. It also includes a demo part where I explain how to allow users to access only specific pages based on their user roles.
Introduction
This article explains about the implementation of custom authorization with user roles using ASP.NET MVC. It prevents unauthorized users to access the pages which they are not supposed to be accessed.
Sample MVC Application for Demonstration
In this demo application, I’m using Visual Studio 2019. I am going to show you how users are disallowed to access the pages which they are not supposed to access. We are using Windows Authentication and users enrolled into a specific user group (Admin/NormalUser) can only be authorized to access the respective pages. For example, user belonging to Admin group can only access the Admin page whereas the user belongs to NormalUser group can only access the NormalUser page.
Step 1: Creating New User Roles in System
Create an Admin Group and Map the User
Launch the Computer Management window. Create a new user group “Admin” and map the windows user to the created group as shown in the below figure:
Create a User Group and Map the User
Launch the Computer Management window. Create a new user group “User” and map the windows user to the created group as shown in the below figure:
Step 2: Creating a Project
In Visual Studio, create a new ASP.NET MVC Web Application (C#) project as shown in the following figure:
Step 3: Configure the UserGroups in Web.config
Configure the newly created groups in config file as shown below:
<appSettings>
<add key="AdminUserRoles" value="Admin" />
<add key="UserRoles" value="NormalUser" />
</appSettings>
Step 4: Adding Enum Class
Add Enum
class “Enums.cs” under the project and add the enum
constants “UserRoles
” as shown below:
namespace CustomAuthorizationWithMVC
{
public static class Enums
{
public enum UserGroups
{
None = 0,
Admin = 1,
NormalUser = 2,
All = 3
}
}
}
Step 5: Adding Login View Model
The following view model class helps the user to store the details of the Logged-in user.
using static CustomAuthorizationWithMVC.Enums;
namespace CustomAuthorizationWithMVC.Models
{
public class LogInViewModel
{
public string LoggedInUser { get; set; }
public bool IsAdmin { get; set; }
public UserGroups UserGroup { get; set; }
}
}
Step 6: Adding Authorization Filter
Add the class file “UserAuthorizeAttribute.cs” under the project and add the below code inside the class file. This class inherits from “AuthorizeAttribute
” and overrides the method “OnAuthorization
” which validates the logged-in groups/roles with the one configured in the web.Config. If user is not enrolled in either of these groups/roles, then the user will be redirected to log-in page without getting access to the requested page.
namespace UI.UserAuthorize
{
using System;
using System.Configuration;
using System.Diagnostics;
using System.Web.Mvc;
using System.Web.Routing;
using static CustomAuthorizationWithMVC.Enums;
using AuthorizeUser.Common;
public sealed class UserAuthorizeAttribute : AuthorizeAttribute
{
#region Constructors
public UserAuthorizeAttribute(params UserGroups[] userRoleTypes)
{
this.AllowedUserRoleTypes = userRoleTypes;
}
#endregion
#region Properties
private string AdminUserRoles { get; } =
ConfigurationManager.AppSettings["AdminUserRoles"];
private string UserRoles { get; } = ConfigurationManager.AppSettings["UserRoles"];
private UserGroups[] AllowedUserRoleTypes { get; set; }
#endregion
#region Public Methods
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext != null)
{
var user = filterContext.RequestContext.HttpContext.User;
base.OnAuthorization(filterContext);
if (!AuthorizeUser.IsAdmin(AllowedUserRoleTypes, AdminUserRoles, user)
&& !AuthorizeUser.IsUser(AllowedUserRoleTypes, UserRoles, user))
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "LogIn", action = "LogIn" }));
}
}
}
#endregion
}
}
Step 7: Adding Authorization Helper Class
This class methods are used by Authorization filter class “UserAuthorizeAttribute
” to check whether the logged-in user belongs to configured Admin
group or NormalUser
group.
namespace AuthorizeUser.Common
{
using System.Linq;
using System.Security.Principal;
using System.Text.RegularExpressions;
using static CustomAuthorizationWithMVC.Enums;
public static class AuthorizeUser
{
public static bool IsAdmin(UserGroups[] allowedAuditUserGroupTypes,
string auditAdminUserGroups, IPrincipal user)
{
bool isAdmin = false;
var adminUserGroups =
Regex.Replace(auditAdminUserGroups, @"\s", string.Empty).Split(',');
if (allowedAuditUserGroupTypes.Any
(allowedGroupType => allowedGroupType == UserGroups.Admin))
{
isAdmin = adminUserGroups.Any(admGrp => user.IsInRole(admGrp));
}
return isAdmin;
}
public static bool IsUser(UserGroups[] allowedAuditUserGroupTypes,
string auditUserGroups, IPrincipal user)
{
bool isUser = false;
var userGroups = Regex.Replace(auditUserGroups, @"\s", string.Empty).Split(',');
if (allowedAuditUserGroupTypes.Any
(allowedGroupType => allowedGroupType == UserGroups.NormalUser))
{
isUser = userGroups.Any(usrGrp => user.IsInRole(usrGrp));
}
return isUser;
}
}
}
Step 8: Adding MVC Controllers
Add the following controller classes under Controllers folder in the project:
- LogInController.cs
- AdminController.cs
- UserController.cs
LogInController.cs
The following controller class helps user to navigate to Login view and enable/disable the Login buttons based on the user roles. Admin login button functionality is to navigate to Admin page and NormalUser log in button is for navigating user to NormalUser page.
using CustomAuthorizationWithMVC.Models;
using System.Configuration;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using static CustomAuthorizationWithMVC.Enums;
namespace CustomAuthorizationWithMVC.Controllers
{
public class LogInController : Controller
{
private string AdminUserRoles { get; } =
ConfigurationManager.AppSettings["AdminUserRoles"];
private string UserRoles { get; } = ConfigurationManager.AppSettings["UserRoles"];
public ActionResult LogIn()
{
bool isAdmin = Regex.Replace(this.AdminUserRoles, @"\s", string.Empty).Split(',')
.Any(admRole => User.IsInRole(admRole));
bool isUser = Regex.Replace(this.UserRoles, @"\s", string.Empty).Split(',')
.Any(usrRole => User.IsInRole(usrRole));
LogInViewModel logInViewModel = new LogInViewModel()
{
LoggedInUser = User.Identity.Name,
UserGroup = this.GetUserRole(isAdmin, isUser)
};
return View(logInViewModel);
}
public ActionResult AdminView()
{
return this.RedirectToAction("RenderAdminView", "Admin");
}
public ActionResult UserView()
{
return this.RedirectToAction("RenderUserView", "User");
}
private bool IsUserInGroup(string groupName)
{
return User.IsInRole(groupName);
}
private UserGroups GetUserRole(bool isAdmin, bool isUser)
{
if (isAdmin && isUser)
{
return Enums.UserGroups.All;
}
if (isAdmin)
{
return Enums.UserGroups.Admin;
}
if (isUser)
{
return Enums.UserGroups.NormalUser;
}
return Enums.UserGroups.None;
}
}
}
AdminController.cs
The following controller class helps the user to navigate to Admin page if he/she had enrolled into Admin role. By making the Authorization filter “UserAuthorize
” annotation before the “AdminController
” class (as highlighted bold in the below code) will validate the logged-in user against the configured Admin roles in web.cofig. If validation passed, it will execute the “RenderAdminView
” method and Navigate to Admin page. Else, it redirects to LogIn page.
using System.Web.Mvc;
using UI.UserAuthorize;
using static CustomAuthorizationWithMVC.Enums;
namespace CustomAuthorizationWithMVC.Controllers
{
[UserAuthorize(UserGroups.Admin)]
public class AdminController : Controller
{
public ActionResult RenderAdminView()
{
return View("Admin");
}
}
}
UserController.cs
The following controller class helps the user to navigate to User page if he/she has enrolled into NormalUser
role. By making the Authorization filter “UserAuthorize
” annotation before the “UserController
” class (as highlighted bold in the below code) will validate the logged-in user against the configured user roles in web.config. If validation passed, it will execute the “RenderUserView
” method and Navigate to User page. Else, it redirects to Login page.
using System.Web.Mvc;
using UI.UserAuthorize;
using static CustomAuthorizationWithMVC.Enums;
namespace CustomAuthorizationWithMVC.Controllers
{
[UserAuthorize(UserGroups.NormalUser)]
public class UserController : Controller
{
public ActionResult RenderUserView()
{
return View("User");
}
}
}
Step 9: Adding MVC Views
Add the following views under Views folder in the project:
- LogIn.cshtml
- Admin.cshtml
- User.cshtml
LogIn.cshtml
In this view, we received the “LogInViewModel
” as model and validate the Logged-in user group against the enum
constants. If logged-in user group is “Admin”, then “Login as Administrator” button is enabled and if logged-in user group is “NormalUser”, then the “Login as NormalUser” button is enabled.
@model CustomAuthorizationWithMVC.Models.LogInViewModel
@{
ViewBag.Title = "LogIn";
}
<h2>LogIn Page.</h2>
<div>
@if (Model.UserGroup == Enums.UserGroups.Admin || Model.UserGroup == Enums.UserGroups.All)
{
<button id="btnAdministrator"
onclick="location.href = '@Url.Action("AdminView", "LogIn")'"
class="btn btn-primary">Login as Administrator</button>
}
@if (Model.UserGroup == Enums.UserGroups.NormalUser ||
Model.UserGroup == Enums.UserGroups.All)
{
<button id="btnAuditUser"
onclick="location.href = '@Url.Action("UserView", "LogIn")'"
class="btn btn-primary">Login as NormalUser</button>
}
@if (Model.UserGroup == Enums.UserGroups.None)
{
<button id="btnClose" onclick="window.close();"
class="btn btn-primary">Close</button>
}
</div>
Admin.cshtml
This view will display the message as “Admin Page”. When Admin navigates to this view:
@{
ViewBag.Title = "Admin";
}
<h2>Admin Page.</h2>
User.cshtml
This view will display the message as “User Page”. When User navigates to this view:
@{
ViewBag.Title = "Admin";
}
<h2>NormalUser Page.</h2>
Step 10: Run the Application
I have enrolled only for “NormalUser
” group. Hence, I can view only the “Login as Normal User” button in Login page when I launch it as shown below:
And able to navigate to Normal User Page on click of Login button.
Being a user of Normal Group, I may still try to access the Admin page by typing the URL in the browser. This is the scenario where the logged-in user is validated by authorization filter and will redirect me back to Login page as I’m the unauthorized user for Admin page as shown below:
History
- 3rd May, 2020 - Initial version