一个简单的ASP.NET MVC下的权限方案

偶然看到博客园里 JadePeng 的 一篇关于ASP.NET MVC下的权限设计的旧文 http://www.cnblogs.com/xiaoqi/archive/2010/01/07/1641570.html,该权限设计中用到5个数据表,利用数据库中的Controller和action记录进行权限判断。

多年前我在一个web form的 web项目里用过类似的方式,当然那里没有controller和action, 主要是将判断函数放在基类里,在页面.cs里调用此函数作为权限判断。

这里提出一个使用XML+数据库+ session(cookie) 的权限方案,旨在简单易懂易用,设计粗劣,大家有兴趣改进。

因为个人觉得在普通的小系统里,角色role是有限的,一个系统里的controller和action总归也是有限的(1K以内?呵呵)。所以我用XML而不是数据库来记录这些。

几点说明:

    1、该权限系统是个网站用的,用户简单,因此不涉及到部门这些信息

    2、基于将角色与controller、action相关联来判断用户是否有权

    3、通过重载AuthorizeAttribute实现

    ----- 前3项COPY自http://www.cnblogs.com/xiaoqi/archive/2010/01/07/1641570.html 

    4. 权限的设定保存于XML之中,权限在用户登录后存储于session(理论上cookie也可以),用户登录后判断权限无需查询数据库。

数据库设计:

    2个数据表,User 和 UserRole,字段简单,不多做解释了。

 

相关XML

1. Role.xml --- 记录系统的所有角色,比如

Role.xml
<?xml version="1.0" encoding="utf-8"?>
<role>
  <item>
    <name>Guest</name>
    <desciption></desciption>
  </item>
  <item>
    <name>Admin1</name>
    <desciption></desciption>
  </item>
  <item>
    <name>RegisterUser</name>
    <desciption>注册用户</desciption>
  </item>
</role>

2. Permission.xml ---- 记录系统所有的操作权限 --- 在MVC里的权限是用Controller和action来判定的,此XML的作用在于提供给UI界面添加、管理系统的所有权限。

    节点说明 -- module 节点为controller的名称,一个controller下的action 和 controller本身组成 permission节点

Permission.xml
  1 <?xml version="1.0" encoding="utf-8"?>
  2 <permissionRoot>
  3   <module name="Home">
  4     <permission>
  5       <controller>Home</controller>
  6       <action>Index</action>
  7     </permission>
  8     <permission>
  9       <controller>Home</controller>
 10       <action>KeepAlive</action>
 11     </permission>
 12     <permission>
 13       <controller>Home</controller>
 14       <action>About</action>
 15     </permission>
 16   </module>
 17   <module name="Account">
 18     <permission>
 19       <controller>Account</controller>
 20       <action>LogOn</action>
 21     </permission>
 22     <permission>
 23       <controller>Account</controller>
 24       <action>LogOff</action>
 25     </permission>
 26     <permission>
 27       <controller>Account</controller>
 28       <action>Register</action>
 29     </permission>
 30     <permission>
 31       <controller>Account</controller>
 32       <action>Lock</action>
 33     </permission>
 34   </module>
 35   <module name="General">
 36     <permission>
 37       <controller>General</controller>
 38       <action>SearchResults</action>
 39     </permission>
 40   </module>
 41   <module name="Book">
 42     <permission>
 43       <controller>Book</controller>
 44       <action>Update</action>
 45     </permission>
 46     <permission>
 47       <controller>Book</controller>
 48       <action>Novel</action>
 49     </permission>
 50     <permission>
 51       <controller>Book</controller>
 52       <action>History</action>
 53     </permission>
 54     <permission>
 55       <controller>Book</controller>
 56       <action>Live</action>
 57     </permission>
 58     <permission>
 59       <controller>Book</controller>
 60       <action>Blog</action>
 61     </permission>
 62     <permission>
 63       <controller>Book</controller>
 64       <action>Military</action>
 65     </permission>
 66     <permission>
 67       <controller>Book</controller>
 68       <action>Other</action>
 69     </permission>
 70     <permission>
 71       <controller>Book</controller>
 72       <action>Detail</action>
 73     </permission>
 74     <permission>
 75       <controller>Book</controller>
 76       <action>HotBook</action>
 77     </permission>
 78     <permission>
 79       <controller>Book</controller>
 80       <action>LatestUpdateBook</action>
 81     </permission>
 82     <permission>
 83       <controller>Book</controller>
 84       <action>Index</action>
 85     </permission>
 86     <permission>
 87       <controller>Book</controller>
 88       <action>GetData</action>
 89     </permission>
 90     <permission>
 91       <controller>Book</controller>
 92       <action>GetBooks</action>
 93     </permission>
 94   </module>
 95   <module name="Books">
 96   <permission>
 97     <controller>Books</controller>
 98     <action>Management</action>
 99   </permission>
100   <permission>
101     <controller>Books</controller>
102     <action>CreateBook</action>
103   </permission>
104   <permission>
105     <controller>Books</controller>
106     <action>Edit</action>
107   </permission>
108   <permission>
109     <controller>Books</controller>
110     <action>Lock</action>
111   </permission>
112   <permission>
113       <controller>Books</controller>
114       <action>Delete</action>
115     </permission>
116   </module>
117   <module name="Role">
118   <permission>
119     <controller>Role</controller>
120     <action>Management</action>
121   </permission>
122   <permission>
123     <controller>Role</controller>
124     <action>AddRole</action>
125   </permission>
126   <permission>
127     <controller>Role</controller>
128     <action>EditRolePermission</action>
129   </permission>
130   <permission>
131       <controller>Role</controller>
132       <action>Delete</action>
133     </permission>
134   </module>
135   <module name="User">
136     <permission>
137       <controller>User</controller>
138       <action>Management</action>
139     </permission>
140     <permission>
141       <controller>User</controller>
142       <action>CreateUser</action>
143     </permission>
144     <permission>
145       <controller>User</controller>
146       <action>Edit</action>
147     </permission>
148     <permission>
149       <controller>User</controller>
150       <action>Delete</action>
151     </permission>
152     <permission>
153       <controller>User</controller>
154       <action>AddToRole</action>
155     </permission>
156     <permission>
157       <controller>User</controller>
158       <action>RemoveFromRole</action>
159     </permission>
160     <permission>
161       <controller>User</controller>
162       <action>CheckUserName</action>
163     </permission>
164   </module>
165   <module name="Config">
166     <permission>
167       <controller>Config</controller>
168       <action>Category</action>
169     </permission>
170     <permission>
171       <controller>Config</controller>
172       <action>Property</action>
173     </permission>
174     <permission>
175       <controller>Config</controller>
176       <action>LinkFrom</action>
177     </permission>
178     <permission>
179       <controller>Config</controller>
180       <action>AddCategoryItem</action>
181     </permission>
182     <permission>
183       <controller>Config</controller>
184       <action>DeleteCategoryItem</action>
185     </permission>
186     <permission>
187       <controller>Config</controller>
188       <action>AddPropertyItem</action>
189     </permission>
190     <permission>
191       <controller>Config</controller>
192       <action>DeletePropertyItem</action>
193     </permission>
194     <permission>
195       <controller>Config</controller>
196       <action>AddLinkFromItem</action>
197     </permission>
198     <permission>
199       <controller>Config</controller>
200       <action>DeleteLinkFromItem</action>
201     </permission>
202   </module>
203 </permissionRoot>

3.RolePermission.xml ---- 记录系统内所有角色的权限记录。结构如下:

 
RolePermission.xml
<?xml version="1.0" encoding="utf-8"?>
<permissionRoot>
  <role name="Guest">
    <permission>
      <controller>Home</controller>
      <action>Index</action>
    </permission>
    <permission>
      <controller>Home</controller>
      <action>KeepAlive</action>
    </permission>
    <permission>
      <controller>Home</controller>
      <action>About</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>LogOn</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>LogOff</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>Register</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>Lock</action>
    </permission>
    <permission>
      <controller>General</controller>
      <action>SearchResults</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Update</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Novel</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>History</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Live</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Blog</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Other</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Detail</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>HotBook</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>LatestUpdateBook</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Index</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>GetData</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>GetBooks</action>
    </permission>
  </role>
  <role name="RegisterUser">
    <permission>
      <controller>Home</controller>
      <action>Index</action>
    </permission>
    <permission>
      <controller>Home</controller>
      <action>KeepAlive</action>
    </permission>
    <permission>
      <controller>Home</controller>
      <action>About</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>LogOn</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>LogOff</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>Register</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>Lock</action>
    </permission>
    <permission>
      <controller>General</controller>
      <action>SearchResults</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Update</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Novel</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>History</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Live</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Blog</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Military</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Other</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Detail</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>HotBook</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>LatestUpdateBook</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Index</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>GetData</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>GetBooks</action>
    </permission>
  </role>
  <role name="Admin1">
    <permission>
      <controller>Home</controller>
      <action>Index</action>
    </permission>
    <permission>
      <controller>Home</controller>
      <action>KeepAlive</action>
    </permission>
    <permission>
      <controller>Home</controller>
      <action>About</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>LogOn</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>LogOff</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>Register</action>
    </permission>
    <permission>
      <controller>Account</controller>
      <action>Lock</action>
    </permission>
    <permission>
      <controller>General</controller>
      <action>SearchResults</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Update</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Novel</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>History</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Live</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Blog</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Military</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Other</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Detail</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>HotBook</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>LatestUpdateBook</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>Index</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>GetData</action>
    </permission>
    <permission>
      <controller>Book</controller>
      <action>GetBooks</action>
    </permission>
    <permission>
      <controller>Books</controller>
      <action>Management</action>
    </permission>
    <permission>
      <controller>Books</controller>
      <action>CreateBook</action>
    </permission>
    <permission>
      <controller>Books</controller>
      <action>Edit</action>
    </permission>
    <permission>
      <controller>Books</controller>
      <action>Lock</action>
    </permission>
    <permission>
      <controller>Books</controller>
      <action>Delete</action>
    </permission>
    <permission>
      <controller>Role</controller>
      <action>Management</action>
    </permission>
    <permission>
      <controller>Role</controller>
      <action>AddRole</action>
    </permission>
    <permission>
      <controller>Role</controller>
      <action>EditRolePermission</action>
    </permission>
    <permission>
      <controller>Role</controller>
      <action>Delete</action>
    </permission>
    <permission>
      <controller>User</controller>
      <action>Management</action>
    </permission>
    <permission>
      <controller>User</controller>
      <action>CreateUser</action>
    </permission>
    <permission>
      <controller>User</controller>
      <action>Edit</action>
    </permission>
    <permission>
      <controller>User</controller>
      <action>Delete</action>
    </permission>
    <permission>
      <controller>User</controller>
      <action>AddToRole</action>
    </permission>
    <permission>
      <controller>User</controller>
      <action>RemoveFromRole</action>
    </permission>
    <permission>
      <controller>User</controller>
      <action>CheckUserName</action>
    </permission>
    <permission>
      <controller>Config</controller>
      <action>Category</action>
    </permission>
    <permission>
      <controller>Config</controller>
      <action>Property</action>
    </permission>
    <permission>
      <controller>Config</controller>
      <action>LinkFrom</action>
    </permission>
    <permission>
      <controller>Config</controller>
      <action>AddCategoryItem</action>
    </permission>
    <permission>
      <controller>Config</controller>
      <action>DeleteCategoryItem</action>
    </permission>
    <permission>
      <controller>Config</controller>
      <action>AddPropertyItem</action>
    </permission>
    <permission>
      <controller>Config</controller>
      <action>DeletePropertyItem</action>
    </permission>
    <permission>
      <controller>Config</controller>
      <action>AddLinkFromItem</action>
    </permission>
    <permission>
      <controller>Config</controller>
      <action>DeleteLinkFromItem</action>
    </permission>
  </role>
</permissionRoot>

流程

流程较为简单,故文字说明。

1.User表用户登录的同时,从UserRole表中查询出用户所拥有的角色,然后在RolePermission.xml里查询得到所拥有角色的所有权限permission列表,每个permission格式为 controller_action,组成一个list,踢出重复项,再转为string,保存于session之中。session 同时保存用户名

2.新建一个filter: UserAuthorizeAttribute,继承AuthorizeAttribute, 重写OnAuthorization。在此方法体内 做判断,如果用户的permission列表里包含当前的controller,action,验证通过,否则反之。

3.对于未登陆用户,默认采用Guest角色的权限。(视系统需要而定)

主要代码

1.UserAuthorizeAttribute.cs

View Code
  1 namespace Clover.Net.Web.Code.Filters
  2 {
  3     /// <SUMMARY> 
  4     /// 自定义AuthorizeAttribute 
  5     /// </SUMMARY> 
  6     public class UserAuthorizeAttribute : AuthorizeAttribute
  7     {
  8         private PermissionRepository _permissionRepository = new PermissionRepository();
  9 
 10         public override void OnAuthorization(AuthorizationContext filterContext)
 11         {
 12             string rolePermissionXml = filterContext.HttpContext.Server.MapPath("/Config/RolePermission.xml");
 13             var user = filterContext.HttpContext.Session["user_Name"];
 14             var permissions = filterContext.HttpContext.Session["user_Permissions"];
 15 
 16             List<string> user_Permissions = new List<string>();
 17 
 18             if (user != null || permissions != null)
 19             {
 20                 string[] userTotalPermissions = permissions.ToString().Split(',');
 21                 foreach (var per in userTotalPermissions)
 22                 {
 23                     user_Permissions.Add(per);
 24                 }
 25             }
 26             //用户为空,赋予Guest  and set up the session
 27             else
 28             {
 29                 string guestTotalPermissions = string.Empty;
 30                 List<PermissionItem> permissionList = _permissionRepository.CurrentRolePermissions(rolePermissionXml, "Guest");
 31                 foreach (var per in permissionList)
 32                 {
 33                     guestTotalPermissions = guestTotalPermissions + "," + per.Controller + "_" + per.Action;
 34                 }
 35                 filterContext.HttpContext.Session["user_Name"] = "Guest";
 36                 filterContext.HttpContext.Session["user_Permissions"] = guestTotalPermissions;
 37 
 38                 string[] userTotalPermissions = guestTotalPermissions.ToString().Split(',');
 39                 foreach (var per in userTotalPermissions)
 40                 {
 41                     user_Permissions.Add(per);
 42                 }
 43             }
 44 
 45             string controller = filterContext.RouteData.Values["controller"].ToString();
 46             string action = filterContext.RouteData.Values["action"].ToString();
 47 
 48             string id = String.Empty;
 49             if (filterContext.RouteData.Values["id"] != null)
 50             {
 51                id = filterContext.RouteData.Values["id"].ToString();
 52             }
 53             var isAllowed = this.IsAllowed(controller, action, user_Permissions);
 54 
 55             if (!isAllowed)
 56             {
 57                 //filterContext.RequestContext.HttpContext.Response.Write("无权访问");
 58                 //filterContext.RequestContext.HttpContext.Response.End();
 59 
 60                 //filterContext.RequestContext.HttpContext.Response.Redirect("../Account/LogOn");
 61 
 62                 string returnUrl = String.Empty;
 63                 if (String.IsNullOrEmpty(id))
 64                 {
 65                     returnUrl = "/" + controller + "/" + action;
 66                 }
 67                 else
 68                 {
 69                     returnUrl = "/" + controller + "/" + action + "/" + id;
 70                 }
 71 
 72                 filterContext.Controller.ViewData["ReturnUrl"] = returnUrl;
 73 
 74                 if (filterContext.HttpContext.Session["user_Name"].ToString() == "Guest")
 75                 {
 76                     filterContext.Controller.ViewData["Title"] = "请登录";
 77                     filterContext.Controller.ViewData["Description"] = "您还没有登录,请登录!";
 78                     //filterContext.RequestContext.HttpContext.Response.Redirect("~/Account/LogOn?ReturnUrl=" + returnUrl);
 79                 }
 80                 else
 81                 {
 82                     filterContext.Controller.ViewData["Title"] = "权限问题";
 83                     filterContext.Controller.ViewData["Description"] = "对不起,你无权访问此页面,请联系管理员!";
 84                 }
 85 
 86                 filterContext.Result = new ViewResult()
 87                 {
 88                     ViewName = "Error",
 89                     ViewData = filterContext.Controller.ViewData,
 90                 };
 91             }
 92 
 93         }
 94 
 95         /// <SUMMARY> 
 96         /// 判断是否允许访问 
 97         /// </SUMMARY> 
 98         /// <SPAN name="user"> </SPAN>用户 
 99         /// <SPAN name="controller"> </SPAN>控制器 
100         /// <SPAN name="action"> </SPAN>action 
101         /// <RETURNS>是否允许访问</RETURNS> 
102         public bool IsAllowed(string controller, string action, List<string> user_Permissions)
103         {
104             string permission = controller + "_" + action;
105 
106             //如果是登陆,默认通过
107             if (permission == "Account_LogOn" || permission == "Account_Logon" || permission == "Account_LogOff" || permission == "Account_Register" || permission == "User_CheckUserName")
108             {
109                 return true;
110             }
111 
112             if (user_Permissions.Contains(permission))
113             {
114                 return true;
115             }
116             // 默认禁止访问 
117             return false;
118         }
119     }
120 }

 2.SetUpUser函数,在用户登录验证通过之后调用,作用是将用户名和用户权限列表保存于session之中

View Code
        public void SetUpUser(string userName)
        {
            string userTotalPermissions = string.Empty;
            List<string> userTotalPermissionsList = new List<string>();
            List<string> userRoles = this.GetUserRoles(userName);
            foreach (var role in userRoles)
            {
                List<PermissionItem> permissionList = _IPermissionRepository.CurrentRolePermissions(rolePermissionXml, role);
                if (permissionList != null)
                {
                    foreach (var per in permissionList)
                    {
                        string permissionText = per.Controller + "_" + per.Action;
                        userTotalPermissionsList.Add(permissionText);
                    }
                }
            }
            List<string> userPermissionsList = userTotalPermissionsList.Distinct().ToList();
            foreach (var per in userPermissionsList)
            {
                userTotalPermissions = userTotalPermissions + "," + per;
            }
            Session["user_Name"] = userName;
            Session["user_Permissions"] = userTotalPermissions.ToString();
        }

具体使用

只需要在 BaseController 顶部添加一个 [UserAuthorize]

 -------------------------------------------------------------------

测试界面

纯属给大家看下结果,呵呵,没有权限被拒绝

 
 
管理某个角色的权限:
 
 
 
管理用户的角色
 
 
 

后记

本方案较为简单,适合小项目用哈。当前用户的权限列表存储于session中,再次判断权限时候无需再次读取数据库。

还有很多问题和不足之处,欢迎大家指正。

原文地址:https://www.cnblogs.com/qingzhou/p/2773204.html