利用RBAC模型实现一个通用的权限管理系统

       本文主要描述一个通用的权限系统实现思路与过程。也是对这次制做权限管理模块的总结。html

       制做此系统的初衷是为了让这个权限系统得以“通用”。就是生产一个web系统经过调用这个权限系统(生成的dll文件),web

就能够实现权限管理。这个权限系统会管理已生产系统的全部用户,菜单,操做项,角色分配,权限分配,日志等内容。数据库

  实现此功能从正常访问和非法访问两个方面入手。正常访问即用户登陆系统后只能看到或操做本身拥有的菜单;非法访问即框架

经过拼写url等途径访问系统的某个功能;因此程序除了实现用户登陆后获取用户拥有的菜单权限,更要挡住用户的非法请求。两数据库设计

者缺一不可。ide

一.概念

     实现这个功能主要利用RBAC权限设计模型,英文(Role-Based Access Control)译为基于角色的权限管理又叫基于角色的url

访问控制。spa

二.数据库设计

 1.系统表:由于要达到"通用",因此这个表会记录各个系统。其余用户、菜单、操做、权限表每条记录都会对应系统代码。操作系统

 

 字段说明:Code      —> 系统标识代码设计

                  SysName  —> 系统名称

2.菜单表:记录菜单。每一个功能当成一个菜单,菜单有url属性,用户经过点击菜单来访问对应功能;

 

 字段说明:ID                  —> 主键,自增标识

                  MenuName     —> 菜单名称

        PageUrl                —> 菜单对应url

        PId                   —> 菜单父级Id

           Lv        —> 菜单等级,分一级菜单和二级菜单

                  ControllerAction  —> 菜单惟一标识,用来作权限控制

                  SystemCode    —> 系统标识代码

3.操做表:此表主要是为了判断用户是否有来操做某个具体功能,如经常使用的【删除】功能等操做都放在这个表里;

 

 字段说明:ID                —> 主键,自增标识

                  OprateName   —> 操做名称

           OperateCode     —> 操做标识代码

                  SystemCode       —> 系统标识代码

4.用户表:记录全部系统的使用用户。记录用户帐号、密码等信息;

 

 字段说明:ID            —> 主键,自增标识

                  UserName   —> 用户登陆名称

        UserPwd         —> 用户登陆密码

                  SystemCode   —> 系统标识代码

5.角色表:这是RBAC设计不可缺乏的,记录角色信息,不一样级别的角色拥有不一样的权限。给用户分配角色也用到它;

 

 字段说明:ID             —> 主键,自增标识

                  RoleName    —> 角色名称

                  SystemCode   —> 系统标识代码

6.权限表:存放用户的权限信息。在这个系统里个人设计是每一个菜单,每一个操做都对应一个权限记录。因此有一个字段[ActionType]

来区分是菜单仍是操做;

 

 字段说明:ID             —> 主键,自增标识

                  PowerName —> 权限名称

        ActionId          —> 菜单或操做ID

        ActionType      —> 区分是菜单或操做

                  SystemCode    —> 系统标识代码

7.用户对应角色表:这个表负责关联用户和角色的关系。因为初次使用RBAC模型,又为了快速投入使用,所以在此次使用中没有

考虑一对多的角色。因此在这个系统里用户和角色都是一对一的关系,每一个用户对应一个角色;

 

 字段说明:ID             —> 主键,自增标识

                  UserId           —> 用户ID

        RoleId              —> 角色ID

                  SystemCode    —> 系统标识代码

 

8.角色对应权限表:这个表负责管理角色和权限的关系。角色和权限属于一对多的关系,每一个角色对应多个权限;

 

 字段说明:ID             —> 主键,自增标识

                  RoleId           —> 角色ID

        PowerId           —> 权限ID

                  SystemCode    —> 系统标识代码

9.日志表:这个应该容易理解,日志表记录用户操做系统的痕迹,像用户信息、访问url、时间等。

 字段说明:ID             —> 主键,自增标识

                  UserId           —> 操做名称

        VisitUrl            —> 操做标识代码

                  Remark           —> 系统标识代码

                  CreateTime     —> 建立时间

                  SystemCode   —> 系统标识代码

 

三.程序设计

      上面说了数据库的构造,接下来说一下这次程序的设计方案。开篇已经提过为了通用此项目最终生成dll文件以便其余系统调用,

固然你也能够作成webservice,还能知足跨平台。

       这个系统不与任何业务系统公用数据访问层和业务逻辑层。即便二者使用一个相同的数据库,这个系统仍是拥有独立的数据访

问层和业务逻辑层,这个状况只限于一个实现权限管理的“权限后台”。

       在此我用了三层,添加了一个接口Service。其余系统只能访问这个接口调用本身须要的方法。这样作对于系统自己有利于避免

方法被任意调用,能实现途径不一。对使用者也简洁明了。为了达到这个目的能够用关键字internal修饰数据访问层和业务逻辑层

的类。程序结构以下图:

 

  继续说说这个接口提供了哪些方法和属性吧。

1.当前登录用户:在系统中很多地方要用到它,好比展现登录用户的帐号,角色等,存放登陆用户可使用Session,也可以使用Redis;

2.登陆/退出方法;

2.登录用户有权限访问的菜单集合:提供使用用户正常访问的菜单,例如树形菜单等;

3.子菜单集合:方法2也可实现,这个只不过多一个服务而已;

4.判断操做权限的方法:数据库中有一个操做表,经过操做代码去权限表里查询。判断登录用户是否拥有某一个操做的权限,例如

“删除”功能;

5.日志集合:知足各个系统查看日志的须要。

四.权限和日志

  这里的权限是为了挡住非正常途径的访问。实现思路是经过用户访问的url跟用户能够访问的菜单属性【ControllerAction】一一

对比。为了便于理解,在此用开发实例说明一下

       我作业务系统时UI框架用的是MVC4.0,他很好的支持Filter。所以在权限系统三层的基础上加了一个Filter文件夹,建立PowerAttribute

,提供验证登陆和验证权限两个类。

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class LoginAttribute : ActionFilterAttribute
    {
        /// <summary> 登陆验证 </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var loginUser = UserService.LoginUser;
            base.OnActionExecuting(filterContext);
            if (loginUser.ID <= 0)
            {
                filterContext.Result = new RedirectResult("/home/login");
                filterContext.Result.ExecuteResult(filterContext);
            }
        }
    }
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class PowerAttribute : LoginAttribute
    {
        /// <summary> 访问权限验证 </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            LoginAttribute loginAttribute = new LoginAttribute();
            loginAttribute.OnActionExecuting(filterContext);

            var routeAction = HttpContext.Current.Request.RequestContext.RouteData.Values["Controller"] + "." + 
HttpContext.Current.Request.RequestContext.RouteData.Values["Action"]; List<Menu> userOwnMenuList = MenuService.GetUserOwnMenuList().ResultModel as List<Menu> ?? new List<Menu>(); var isHavepermission = userOwnMenuList.FirstOrDefault(m => m.ControllerAction.ToLower() == routeAction.ToLower()) != null; if (!isHavepermission) { HttpContext.Current.Response.Write("您没有权限访问"); HttpContext.Current.Response.End(); } } }

  访问【用户列表】时,只需在对应的Action上添加特性Power便可。

    // GET: /User/List
    // 用户列表页
    [Power]
    [Log(Desc = "查看用户列表")]
    public ActionResult List(string code = "", int page = 1)

  日志实现同上,就再也不叙述了。整篇文字偏多,没有写实现接口的代码,是由于这些方法实现都很基础。不便登大雅之堂。

相关文章
相关标签/搜索