目录
介绍
本文介绍了使用ASP.NET MVC通过用户角色实现自定义授权的方法。它可以防止未经授权的用户访问不应被访问的页面。
示例MVC应用程序进行演示
在此演示应用程序中,我使用的是Visual Studio 2019。我将向您展示如何禁止用户访问不应访问的页面。我们正在使用Windows身份验证,并且仅被授权访问特定用户组(Admin/NormalUser)的用户才能访问相应页面。例如,属于Admin组的用户只能访问Admin页面,而属于Normal User组的用户只能访问NormalUser页面。
步骤1:在系统中创建新的用户角色
创建一个管理员组并映射用户
启动计算机管理窗口。创建一个新的用户组“Admin”,并将Windows用户映射到创建的组,如下图所示:
创建用户组并映射用户
启动计算机管理窗口。创建一个新的用户组“User”,并将Windows用户映射到创建的组,如下图所示:
步骤2:创建项目
在Visual Studio中,创建一个新的ASP.NET MVC Web应用程序(C#)项目,如下图所示:
步骤3:在Web.config中配置用户组
在配置文件中配置新创建的组,如下所示:
<appSettings>
<add key="AdminUserRoles" value="Admin" />
<add key="UserRoles" value="NormalUser" />
</appSettings>
步骤4:添加枚举类
在项目下添加Enum “Enums.cs”类,并添加enum常量“UserRoles”,如下所示:
namespace CustomAuthorizationWithMVC
{
public static class Enums
{
public enum UserGroups
{
/// <summary>
/// No roles assigned
/// </summary>
None = 0,
/// <summary>
/// Admin role.
/// </summary>
Admin = 1,
/// <summary>
/// User role.
/// </summary>
NormalUser = 2,
/// <summary>
/// Both Administrator and Normal user roles.
/// </summary>
All = 3
}
}
}
步骤5:添加登录视图模型
以下视图模型类可帮助用户存储已登录用户的详细信息。
using static CustomAuthorizationWithMVC.Enums;
namespace CustomAuthorizationWithMVC.Models
{
public class LogInViewModel
{
/// <summary>
/// Gets or sets the LoggedInUser once Authenticated.
/// </summary>
public string LoggedInUser { get; set; }
/// <summary>
/// Gets or sets the Admin flag true/false.
/// </summary>
public bool IsAdmin { get; set; }
/// <summary>
/// Gets or sets the User Role Type.
/// </summary>
public UserGroups UserGroup { get; set; }
}
}
步骤6:添加授权过滤器
在项目下添加类文件“UserAuthorizeAttribute.cs”,并将以下代码添加到类文件中。此类继承自“AuthorizeAttribute”,并重写了方法“OnAuthorization”,该方法使用web.Config中配置的方法验证登录的组/角色。如果用户未注册到这两个组/角色中,则该用户将被重定向到登录页面,而无权访问所请求的页面。
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
/// <summary>
/// Initializes a new instance of the <see cref="UserAuthorizeAttribute" /> class.
/// </summary>
/// <param name="allowedGroupTypes">allowed group types</param>
public UserAuthorizeAttribute(params UserGroups[] userRoleTypes)
{
this.AllowedUserRoleTypes = userRoleTypes;
}
#endregion
#region Properties
/// <summary>
/// Gets the admin user roles from configuration file.
/// </summary>
private string AdminUserRoles { get; } =
ConfigurationManager.AppSettings["AdminUserRoles"];
/// <summary>
/// Gets the user roles from configuration file.
/// </summary>
private string UserRoles { get; } = ConfigurationManager.AppSettings["UserRoles"];
/// <summary>
/// Gets or sets the allowed role types retrieved from controller or action method.
/// </summary>
private UserGroups[] AllowedUserRoleTypes { get; set; }
#endregion
#region Public Methods
/// <summary>
/// Method to do the authorization for user.
/// </summary>
/// <param name="filterContext">authorization context.</param>
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext != null)
{
var user = filterContext.RequestContext.HttpContext.User;
base.OnAuthorization(filterContext);
If user does not have any access, redirect him to login page.
if (!AuthorizeUser.IsAdmin(AllowedUserRoleTypes, AdminUserRoles, user)
&& !AuthorizeUser.IsUser(AllowedUserRoleTypes, UserRoles, user))
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "LogIn", action = "LogIn" }));
}
}
}
#endregion
}
}
步骤7:添加授权助手类
授权过滤器类“UserAuthorizeAttribute” 使用此类方法检查登录的用户是否属于已配置的Admin组或NormalUser组。
namespace AuthorizeUser.Common
{
using System.Linq;
using System.Security.Principal;
using System.Text.RegularExpressions;
using static CustomAuthorizationWithMVC.Enums;
/// <summary>
/// Class to check user group
/// </summary>
public static class AuthorizeUser
{
/// <summary>
/// Method to check whether user is admin user
/// </summary>
/// <param name="allowedAuditUserGroupTypes">allowed audit user group types</param>
/// <param name="admUserGroups">admin user groups</param>
/// <param name="user">user</param>
/// <returns>true or false</returns>
public static bool IsAdmin(UserGroups[] allowedAuditUserGroupTypes,
string auditAdminUserGroups, IPrincipal user)
{
bool isAdmin = false;
var adminUserGroups =
Regex.Replace(auditAdminUserGroups, @"\s", string.Empty).Split(',');
//If allowed group is configured for Administrator.
if (allowedAuditUserGroupTypes.Any
(allowedGroupType => allowedGroupType == UserGroups.Admin))
{
isAdmin = adminUserGroups.Any(admGrp => user.IsInRole(admGrp));
}
return isAdmin;
}
/// <summary>
/// Method to check whether user is audit user
/// </summary>
/// <param name="allowedAuditUserGroupTypes">allowed audit user group types</param>
/// <param name="admUserGroups">admin user groups</param>
/// <param name="user">user</param>
/// <returns>true or false</returns>
public static bool IsUser(UserGroups[] allowedAuditUserGroupTypes,
string auditUserGroups, IPrincipal user)
{
bool isUser = false;
var userGroups = Regex.Replace(auditUserGroups, @"\s", string.Empty).Split(',');
If allowed group is configured for Normal user.
if (allowedAuditUserGroupTypes.Any
(allowedGroupType => allowedGroupType == UserGroups.NormalUser))
{
isUser = userGroups.Any(usrGrp => user.IsInRole(usrGrp));
}
return isUser;
}
}
}
步骤8:添加MVC控制器
在项目的Controllers文件夹下添加以下控制器类:
- LogInController.cs
- AdminController.cs
- UserController.cs
LogInController.cs
以下控制器类可帮助用户导航至“登录”视图并根据用户角色启用/禁用“登录”按钮。管理员登录按钮功能用于导航到“管理”页面,而“NormalUser登录”按钮用于将用户导航至“NormalUser”页面。
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
{
/// <summary>
/// Gets the admin user groups from config file.
/// </summary>
private string AdminUserRoles { get; } =
ConfigurationManager.AppSettings["AdminUserRoles"];
/// <summary>
/// Gets the user groups from config file.
/// </summary>
private string UserRoles { get; } = ConfigurationManager.AppSettings["UserRoles"];
// GET: LogIn
public ActionResult LogIn()
{
// Check the user is enrolled into any of the Admin user roles.
bool isAdmin = Regex.Replace(this.AdminUserRoles, @"\s", string.Empty).Split(',')
.Any(admRole => User.IsInRole(admRole));
// Check the user is enrolled into any of the normal user roles.
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
以下控制器类可帮助用户导航到“管理员”页面(如果他/她已注册为“管理员”角色)。通过在“AdminController”类之前添加“授权”过滤器“UserAuthorize”装饰(如下面的代码中突出显示的粗体所示),将针对web.cofig中配置的Admin角色验证登录用户。如果通过验证,它将执行“RenderAdminView”方法并导航到“管理”页面。否则,它将重定向到“登录”页面。
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
以下控制器类可帮助用户在已注册NormalUser角色的情况下导航至“用户”页面。通过在“UserController”类(在下面的代码中以粗体突出显示)之前进行“授权”过滤器“UserAuthorize”装饰,将针对web.config中配置的用户角色验证登录用户。如果通过验证,它将执行“RenderUserView”方法并导航到“用户”页面。否则,它将重定向到“登录”页面。
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");
}
}
}
步骤9:添加MVC视图
在项目的“视图”文件夹下添加以下视图:
- LogIn.cshtml
- Admin.cshtml
- User.cshtml
LogIn.cshtml
在此视图中,我们收到了“LogInViewModel”作为模型,并根据enum常量验证了登录用户组。如果登录的用户组是“Admin”,则启用“以管理员身份登录”按钮;如果登录的用户组是“NormalUser”,则启用“以普通用户身份登录”按钮。
@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
该视图将消息显示为“Admin Page”。当管理员导航到该视图时:
@{
ViewBag.Title = "Admin";
}
<h2>Admin Page.</h2>
User.cshtml
该视图将消息显示为“User Page”。当用户导航到该视图时:
@{
ViewBag.Title = "Admin";
}
<h2>NormalUser Page.</h2>
步骤10:运行应用程序
我只注册了“NormalUser”组。因此,启动时,我只能在“登录”页面中查看“以普通用户身份登录”按钮,如下所示:
并能够通过单击“登录”按钮导航到“普通用户页面 ”。
作为普通组的用户,我仍然可以尝试通过在浏览器中键入URL来访问“管理”页面。在这种情况下,已通过授权过滤器验证了登录用户的身份,由于我是“管理员”页面的未授权用户,因此会将我重定向回到“登录”页面,如下所示: