zoukankan      html  css  js  c++  java
  • ASP.NET MVC 基于角色的权限控制系统的示例教程

    https://www.cnblogs.com/caoyc/p/5663113.html

    上一次在 .NET MVC 用户权限管理示例教程中讲解了ASP.NET MVC 通过AuthorizeAttribute类的OnAuthorization方法讲解了粗粒度控制权限的方法,接下来讲解基于角色的权限控制方法。

    .NET MVC 用户角色权限控制

    基于角色的权限控制方法概述

    基于角色的权限控制系统RBAC(Role Based Access Control)是目前最流行,也是最通用的权限控制系统。所谓基于角色的权限控制,就是将各个操作权限分组,每一个组就是一个角色,举个例子:管理员拥有所有的权限,编辑就只拥有写文章和发布文章的权限,这里的“管理员”和“编辑”就是一个角色——一系列操作权限的集合。我们只需要将某个角色赋予某个用户那么这个用户就拥有这个角色下的权限集合。

    现在我们要做的就是通过把Controller下的每一个Action可以看作是一个权限,然后可以通过方法将每一个权限进行自定义的分组,从而创建一个角色,然后将角色与用户对应起来。

    基于角色的权限控制方法步骤

    步骤一、新建一个RoleAuthorizeAttribute类

    这个类可以拿到ControllerName和ActionName,这样可以根据ControllerName和ActionName判断是什么样的操作,如下面的代码

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.Security;
     6 using System.Web.Mvc;
     7 using System.Web.Routing;
     8 
     9 namespace SampleMVCWebsite
    10 {
    11     public class RoleAuthorizeAttribute : AuthorizeAttribute
    12     {
    13         public override void OnAuthorization(AuthorizationContext filterContext)
    14         {
    15             var isAuth = false;
    16             if (!filterContext.RequestContext.HttpContext.Request.IsAuthenticated)
    17             {
    18                 isAuth = false;
    19             }
    20             else
    21             {
    22                 if (filterContext.RequestContext.HttpContext.User.Identity != null)
    23                 {
    24                     var roleApi = new RoleApi();
    25                     var actionDescriptor = filterContext.ActionDescriptor;
    26                     var controllerDescriptor = actionDescriptor.ControllerDescriptor;
    27                     var controller = controllerDescriptor.ControllerName;
    28                     var action = actionDescriptor.ActionName;
    29                     var ticket = (filterContext.RequestContext.HttpContext.User.Identity as FormsIdentity).Ticket;
    30                     var role = roleApi.GetById(ticket.Version);
    31                     if (role != null)
    32                     {
    33                         isAuth = role.Permissions.Any(x => x.Permission.Controller.ToLower() == controller.ToLower() && x.Permission.Action.ToLower() == action.ToLower());
    34                     }
    35                 }
    36             }
    37             if (!isAuth)
    38             {
    39                 filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "account", action = "login", returnUrl = filterContext.HttpContext.Request.Url, returnMessage = "您无权查看." }));
    40                 return;
    41             }
    42             else
    43             {
    44                 base.OnAuthorization(filterContext);
    45             }
    46         }
    47     }
    48 }
    复制代码

    其中RoleApi是角色对象管理的API,这里需要自己设置角色管理。上面的代码中通过FilterContext的ActionDescriptor对象的ControllerDescriptor就可以获取到ControllerName和ActionName。获取到当前用户的角色后,通过查看用户的权限中是否包含了当前访问的Controller中的方法,就能实现权限验证。这里主要使用了ActionDescriptor和ControllerDescriptor,关于这两个类的介绍可以参考MSDN官网。

    PS:这里用Ticket的Version存储RoleId。你也可以用其他方式。关于Ticket的知识可以参考微软MSDN官方文档,这里不再敖述。

    步骤二、创建DescriptionAttribute类

    这个类是继承Attribute,为的是给Action方法打上描述标签,如下面的代码

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 
     6 namespace SampleMVCWebsite
     7 {
     8     /// <summary>
     9     /// Description Attribute
    10     /// </summary>
    11     public class DescriptionAttribute:Attribute
    12     {
    13         public string Name
    14         {
    15             set;
    16             get;
    17         }
    18         public int No
    19         {
    20             set;
    21             get;
    22         }
    23     }
    24 }
    复制代码

    Name和NO和Permission类中是ControllerName、ActionName和ControllerNo、ActionNO是对应的。

    步骤三、给Controllers打上DescriptionAttribute标签

    使用步骤二创建的DescriptionAttribute标签给Controller标上,以便存储Permission的时候获取信息。如下面的代码:

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.Mvc;
     6 
     7 namespace SampleMVCWebsite.Controllers
     8 {
     9 [Description(No = 1, Name = "用户")]
    10     public class UserController : Controller
    11     {
    12         [RoleAuthorize]
    13         [Description(No = 1, Name = "用户首页")]
    14         public ActionResult Index()
    15         {
    16             return View();
    17         }
    18         [RoleAuthorize]
    19         [Description(No = 1, Name = "用户管理员")]
    20         public ActionResult Manage()
    21         {
    22             return View();
    23         }
    24         [RoleAuthorize]
    25         [Description(No = 1, Name = "用户详情")]
    26         public ActionResult Detail()
    27         {
    28             return View();
    29         }
    30     }
    31 }
    复制代码

    步骤四、生成权限控制列表

    步骤一种有一个role.Permissions,这个Permissions就是当前用户所拥有的权限集合,在实际的项目开发中是把它存储在数据库关系表中的,我们可以将Permissions类如下面的代码这样定义

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5  
     6 namespace SampleMVCWebsite
     7 {
     8     public class Permission
     9     {
    10         /// <summary>
    11         /// Permission Id
    12         /// </summary>
    13         public virtual int Id
    14         {
    15             set;
    16             get;
    17         }
    18         /// <summary>
    19         /// Permission Action No
    20         /// </summary>
    21         public virtual int ActionNo
    22         {
    23             set;
    24             get;
    25         }
    26  
    27         /// <summary>
    28         /// Controller No
    29         /// </summary>
    30         public virtual int ControllerNo
    31         {
    32             set;
    33             get;
    34         }
    35 
    36         /// <summary>
    37         /// Controller Name
    38         /// </summary>
    39         public virtual string ControllerName
    40         {
    41             set;
    42             get;
    43         }
    44 
    45         /// <summary>
    46         /// Permission Action Name
    47         /// </summary>
    48         public virtual string ActionName
    49         {
    50             set;
    51             get;
    52         }
    53  
    54         /// <summary>
    55         /// Controller
    56         /// </summary>
    57         public virtual string Controller
    58         {
    59             set;
    60             get;
    61         }
    62 
    63         /// <summary>
    64         /// Action
    65         /// </summary>
    66         public virtual string Action
    67         {
    68             set;
    69             get;
    70         }
    71     }
    72 }
    复制代码

    属性Controller和Action记录的是权限,ControllerName和ActionName用于显示UI,ControllerNo和ActionNo用于显示顺序控制。其余根据上面的代码注释应该很好理解,这里就不一一陈述了。

    因此你需要将Action输入数据库中来实现RoleApi。手动输入如果方法少还好,但是多了就比较麻烦,这样我们可以使用.NET的反射机制来进行权限的创建。先看下面的代码:

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.Mvc;
     6 using SampleMVCWebsite.Controllers;
     7 
     8 namespace SampleMVCWebsite
     9 {
    10     public class InstallController
    11     {
    12         public class InstallController : Controller
    13         {
    14             public ActionResult Index()
    15             {
    16                 return View();
    17             }
    18 
    19             [HttpPost]
    20             public ActionResult Index()
    21             {
    22                 try
    23                 {
    24                     var roleService = new RoleApi();
    25                     #region init permission
    26                     CreatePermission(new UserController());
    27                     #endregion
    28 
    29                     var allDefinedPermissions = roleService.GetDefinedPermissions();
    30 
    31                     #region 管理员角色初始化
    32                     var adminPermissions = new List<RolePermissionInfo>();
    33                     foreach (var d in allDefinedPermissions)
    34                     {
    35                         adminPermissions.Add(new RolePermissionInfo {Permission = d, });
    36                     }
    37                     int adminRoleId = roleService.AddRole(new RoleInfo
    38                     {
    39                         Name = "管理员",
    40                         Description = "",
    41                         Permissions = adminPermissions,
    42                         AddDate = DateTime.Now,
    43                     });
    44                     #endregion
    45                     return RedirectToAction("Admin", "Index");
    46                 }
    47                 catch (Exception ex)
    48                 {
    49                     ModelState.AddModelError("", ex.Message);
    50                     return View();
    51                 }
    52             }
    53             private void CreatePermission(Controller customController)
    54             {
    55                 var roleApi = new RoleApi();
    56 
    57                 var controllerName = "";
    58                 var controller = ""; var controllerNo = 0;
    59                 var actionName = ""; var action = ""; var actionNo = 0;
    60                 var controllerDesc = new KeyValuePair<string, int>();
    61 
    62                 var controllerType = customController.GetType();
    63 
    64                 //remove controller posfix
    65                 controller = controllerType.Name.Replace("Controller", "");
    66                 controllerDesc = Getdesc(controllerType);
    67                 if (!string.IsNullOrEmpty(controllerDesc.Key))
    68                 {
    69                     controllerName = controllerDesc.Key;
    70                     controllerNo = controllerDesc.Value;
    71                     foreach (var m in controllerType.GetMethods())
    72                     {
    73                         var mDesc = GetPropertyDesc(m);
    74                         if (string.IsNullOrEmpty(mDesc.Key)) continue;
    75                         action = m.Name;
    76                         actionName = mDesc.Key;
    77                         actionNo = mDesc.Value;
    78                         roleApi.CreatePermissions(actionNo, controllerNo, actionName, controllerName, controller, action);
    79                     }
    80                 }
    81             }
    82             private KeyValuePair<string, int> Getdesc(Type type)
    83             {
    84                 var descriptionAttribute = (DescriptionAttribute)(type.GetCustomAttributes(false).FirstOrDefault(x => x is DescriptionAttribute));
    85                 if (descriptionAttribute == null) return new KeyValuePair<string, int>();
    86                 return new KeyValuePair<string, int>(descriptionAttribute.Name, descriptionAttribute.No);
    87             }
    88             private KeyValuePair<string, int> GetPropertyDesc(System.Reflection.MethodInfo type)
    89             {
    90                 var descriptionAttribute = (DescriptionAttribute)(type.GetCustomAttributes(false).FirstOrDefault(x => x is DescriptionAttribute));
    91                 if (descriptionAttribute == null) return new KeyValuePair<string, int>();
    92                 return new KeyValuePair<string, int>(descriptionAttribute.Name, descriptionAttribute.No);
    93             }
    94         }
    95     }
    96 }
    97 上面的代码首先通过Getdesc来获取Controller的描述,GetPropertyDesc
    复制代码
    方法获取方法的描述,这里的方法就是一个独立的权限,然后通过roleApi的CreatePermissions方法将权限的数据写入到数据库中,将数据写入数据库的代码就需要根据自己的数据库读写方法去实现了,强烈建议使用Linq对数据库进行读写。然后再通过roleApi获取到所有的权限并且将所有的权限绑定到Admin角色,保存对应关系。这样我们就完成了权限控制列表生成并且初始化了管理员用户。

    通过上面的示例就可以完成ASP.NET MVC 基于角色的权限控制系统,上面的代码中的roleApi需要自己写代码实现对数据库的操作,数据模型就是权限、角色、用户的数据表以及权限月角色以及角色与用户的关系表。

  • 相关阅读:
    Vue DatePicker和不可用
    API图片路径和超链接语义化转换
    jQuery常用插件大全
    前端面试必备技巧整理
    堆与堆排序/Heap&Heap sort
    第k大的数
    POJ 2083 Fractal 分形题目
    最大子数组问题/Maximum Subarray
    一个简单的随机数生成算法
    成绩排序
  • 原文地址:https://www.cnblogs.com/wfy680/p/12402943.html
Copyright © 2011-2022 走看看