MVC4 Simplemembership实现用户权限管理-权限控制

MVC4 Simplemembership实现用户权限管理-权限控制

上篇文章我们对默认的Membership数据库进行了扩展,接下来实现对具体的Controller和Action进行控制。

我们使用mvc的AuthorizeAttribute来实现对Controller and Action权限控制。类似下面效果

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.Mvc;
  6. using TYStudio;
  7.  
  8. namespace TYStudioSimplemembership.Controllers
  9. {
  10.     /// <summary>
  11.     /// 这是一个产品权限的测试Controller
  12.     /// </summary>
  13.     ///
  14.     [Authorize]
  15.     [InitializeSimpleMembership]
  16.     public class ProductController : Controller
  17.     {
  18.         [TYStudioAuthorize("查询产品")]
  19.         public ActionResult Index()
  20.         {
  21.             return View();
  22.         }
  23.  
  24.         [TYStudioAuthorize("添加产品")]
  25.         public ActionResult Create()
  26.         {
  27.             return View();
  28.         }
  29.  
  30.         [TYStudioAuthorize("修改产品")]
  31.         public ActionResult Edit()
  32.         {
  33.             return View();
  34.         }
  35.  
  36.         [TYStudioAuthorize("删除产品")]
  37.         public ActionResult Delete()
  38.         {
  39.             return View();
  40.         }
  41.     }
  42. }

首先介绍一下上面以前的Permission表和PermissionsInRoles表的使用,Permission表要存储各个Action的名字(例如一个一个controller中的曾删改查各个Action),或者自己起一个别名,别名主要用于给配置权限的管理人员使用。PermissionsInRoles表就是存储权限和角色关系的了。例如管理员角色具有所有增删改查权限,一般用户角色只有查看权限,我们可以在这里配置。

接下来我们建立一个自己的TYStudioAuthorizeAttribute继承AuthorizeAttribute,并重写AuthorizeCore和HandleUnauthorizedRequest方法。

代码如下:(接下来会解释各个函数的用途)

  1. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
  2.     public class TYStudioAuthorizeAttribute : AuthorizeAttribute
  3.     {
  4.         private readonly bool _authorize;
  5.  
  6.         private bool _isPermissionFail = false;
  7.  
  8.         public TYStudioAuthorizeAttribute()
  9.         {
  10.             if (HttpContext.Current.User.Identity.Name != "")
  11.             {
  12.                 _authorize = true;
  13.             }
  14.             else
  15.             {
  16.                 _authorize = false;
  17.             }
  18.         }
  19.  
  20.         public TYStudioAuthorizeAttribute(string permission)
  21.         {
  22.             if (HttpContext.Current.User.Identity.Name != "")
  23.             {
  24.                 _authorize = PermissionManager.CheckUserHasPermision(HttpContext.Current.User.Identity.Name, permission);
  25.                 if (_authorize == false)
  26.                 {
  27.                     _isPermissionFail = true;
  28.                 }
  29.             }
  30.             else
  31.             {
  32.                 _authorize = false;
  33.             }
  34.             //_authorize = true;
  35.         }
  36.  
  37.         protected override bool AuthorizeCore(HttpContextBase httpContext)
  38.         {
  39.             return _authorize;
  40.         }
  41.  
  42.         protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
  43.         {
  44.             if (_isPermissionFail)
  45.             {
  46.                 filterContext.HttpContext.Response.Redirect("/Admin/PermissionError");
  47.             }
  48.             else
  49.             {
  50.                 base.HandleUnauthorizedRequest(filterContext);
  51.             }
  52.  
  53.         }
  54.     }

首先看一下构造函数TYStudioAuthorizeAttribute(string permission),接受一个permission字符串,这个就是Permission表中的数据,对应着每个Action。

在这个构造参数里判断当前用户是否具有permission这个权限。PermissionManager.CheckUserHasPermision(HttpContext.Current.User.Identity.Name, permission),如果有赋值true给_authorize,表示当前用户有权限访问这个Action。如果没有赋值false给_authorize。

PermissionManager这个类主要是取得当前登录用户的角色,然后通过PermissionsInRoles表中的数据判断是否有这个权限,下面是PermissionManager的code,第一次取出所有权限放在缓存里面。

  1. using System;
  2. using System.Xml;
  3. using System.IO;
  4. using System.Web;
  5. using System.Web.Caching;
  6. using System.Collections.Generic;
  7. using System.Configuration;
  8. using System.Web.Security;
  9. using System.Linq;
  10. using WebMatrix.WebData;
  11.  
  12. namespace TYStudio
  13. {
  14.     public class PermissionManager
  15.     {
  16.         public static bool CheckUserHasPermision(string userName, string permissionName)
  17.         {
  18.             List<Role> roleList = new List<Role>();
  19.             List<PermissionsInRoles> permissionsInRolesList = new List<PermissionsInRoles>();
  20.             if (HttpRuntime.Cache.Get("Roles") == null)
  21.             {
  22.                 using (TYStudioMembershipContext db = new TYStudioMembershipContext())
  23.                 {
  24.                     roleList = db.Roles.AsEnumerable<Role>().ToList<Role>();
  25.  
  26.                     HttpRuntime.Cache.Insert("Roles", roleList);
  27.                 }
  28.             }
  29.  
  30.             if (HttpRuntime.Cache.Get("PermissionsInRoles") == null)
  31.             {
  32.                 using (TYStudioMembershipContext db = new TYStudioMembershipContext())
  33.                 {
  34.                     permissionsInRolesList = db.PermissionsInRoles
  35.                                                 .Include("Permission").Include("Role")
  36.                                                 .AsEnumerable<PermissionsInRoles>().ToList<PermissionsInRoles>();
  37.                     HttpRuntime.Cache.Insert("PermissionsInRoles", permissionsInRolesList);
  38.                 }
  39.             }
  40.  
  41.             string[] currentRoles = new string[] { };
  42.             if (HttpRuntime.Cache.Get("CurrentRoles") == null)
  43.             {
  44.  
  45.                 currentRoles = Roles.GetRolesForUser(userName);
  46.                 HttpRuntime.Cache.Insert("CurrentRoles", currentRoles);
  47.             }
  48.  
  49.             currentRoles = HttpRuntime.Cache.Get("CurrentRoles") as string[];
  50.             roleList = HttpRuntime.Cache.Get("Roles") as List<Role>;
  51.             permissionsInRolesList = HttpRuntime.Cache.Get("PermissionsInRoles") as List<PermissionsInRoles>;
  52.  
  53.             foreach (var roleName in currentRoles)
  54.             {
  55.                 List<Permission> permissionList = permissionsInRolesList.Where(e => e.Role.RoleName == roleName)
  56.                                                                             .Select(e => e.Permission).ToList<Permission>();
  57.  
  58.                 foreach (var permission in permissionList)
  59.                 {
  60.                     if (permission.PermissionName == permissionName)
  61.                     {
  62.                         return true;
  63.                     }
  64.                 }
  65.             }
  66.  
  67.             return false;
  68.         }
  69.     }
  70. }

在AuthorizeCore中我们直接返回_authorize。(当然验证权限的代码完全可以放到这个函数里面)

当返回值为true的时候,系统会允许当前用户处理Action的请求,当返回false的时候,就需要重写的另外一个方法HandleUnauthorizedRequest(AuthorizationContext filterContext),我们可以在这里控制用户没有权限的时候,新建一个错误跳转的页面并加上相应的提示。

文章开始代码中的,查看产品,查看产品详细内容,添加产品,修改产品,删除产品就是Permissions表中存的具体权限数据。

本篇文章只是一个提供意思使用Simplemembership的思路,希望能给你一些灵感,如果有什么问题或者想要源代码,可以留下评论,我会及时回复的。

原创文章,转载请注明出处,谢谢。



26 评论

  1. fabrice   •  

    这样设计是否需要手动把所有Action(或别名)都添加到数据库中呢?能否通过反射机制把所有的Action名称(或别名)读取出来提供选择呢?

    • 天丶屹   •     作者

      你的这个建议很好,但是即使把所有的Action名称得到,一样需要进行别名配置。代码的Action是用户是看不懂的。

      • fabrice   •  

        其实就是,能否把别名也反射出去呢,哈哈

  2. fabrice   •  

    可以发一份代码给我吗?

    • 天丶屹   •     作者

      给我一下你的邮箱吧,我发给你。

        • 天丶屹   •     作者

          已发送给你一个全新的版本思路是一样的,发送给你的是一个后台权限管理系统可以直接使用。

          • fabrice   •  

            非常感谢。先研究,有问题再留言。或者给您发邮件。

          • fabrice   •  

            我在调试你的代码的时候,发现你扩展的model并没有新建数据表,是需要手动创建吗?

          • 天丶屹   •     作者

            你需要修改一下,TYStudioUsersConnectionString,改成你本地数据库的用户名密码。

          • fabrice   •  

            那个我改了,也生成表了,不过是MVC4的表,至于Permission那些扩展的表并没有建立。

          • 天丶屹   •     作者

            416362007你加我qq

  3. Jarrett   •  

    求源码!jarrett_zhou@sina.cn

    • 天屹   •     作者

      看这篇文章有下载,http://www.tystudio.net/2013/03/20/mvc4-simplemembership-permission-system/

  4. Jarrett   •  

    呵呵,我的是VS2010打不开项目,我已经下载,我有个问题想请教你,就是MVC4中怎么操作2个实体多对多关系 的那张映射表,也是说用户 和权限的关系角色表EF是怎么操作的!我是新手还望赐教!

    • 天屹   •     作者

      恩,项目是VS2012的工程开发的,2010我记得是mvc3吧,建好主外键关系之后可以直接用点的方式点出来关联的表,你说有点笼统,能具体一些么

  5. Jarrett   •  

    我装了插件也能做mvc4,比如说一张用户表,一张权限表,我现在呀给用户添加权限,怎么实现!

    • 天屹   •     作者

      一般的是用户和角色关联,角色和权限关联。 如果你不用角色,直接用户和权限关联,建一个UserPermission表,里面有User_ID,Permission_ID,两个分别建好外键,添加关系的时候,直接new 一个UserPermission给两个id赋值后保存就可以了,前提是还得有一个Permission表。

  6. 瞬间   •  

    扩展的AuthorizeAttribute在程序第一次运行时被调用执行,当重新赋予新的权限时,该方法就不执行了。使用一个赋予了新权限的用户登录后,新权限并没有起作用,即没有在执行具体action时调用AuthorizeAttribute。求解。

    • 天屹   •     作者

      现在这个程序在前台直接添加新权限是不起作用的,需要在后台代码中添加相应的权限。这里有点说不清楚,你可以再联系页面找到我的qq加我,咱们qq直接交流。

  7. spring   •  

    好文,
    需要源码,网上的源码无法下载
    我的邮箱284171004@qq.com

  8. das   •  

    bucuo

  9. zz   •  

    可以控制到页面上的按钮权限不

    • 天屹   •     作者

      目前这个不能控制到按钮

  10. zz   •  

    还有你能发一份源码给我不? 305576089@qq.com 在弄用户权限设计到页面按钮的时候不知道怎么处理。

    • 天屹   •     作者

      这个控制不到页面的按钮

瞬间进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>