精华内容
下载资源
问答
  • 通用权限系统设计

    2013-08-21 14:02:38
    权限设计,通用权限系统设计,设计中设计到Role,Rule, 主要权限以用户权限level,数据权限level,功能权限level已经系统权限level和平台权限level来考虑权限的设计
  • 通用权限系统设计通用权限系统设计通用权限系统设计通用权限系统设计通用权限系统设计通用权限系统设计通用权限系统设计通用权限系统设计通用权限系统设计
  • 网上管理系统的权限设计似乎都是使用关系数据库的,这次我们的功能权限不再使用关系型数据库,直接使用对象数据库,体会一下面向对象的数据库在权限系统设计中的使用,因此也就不存在传统意义的数据库设计了。...

    网上管理系统的权限设计似乎都是使用关系数据库的,这次我们的功能权限不再使用关系型数据库,直接使用对象数据库,体会一下面向对象的数据库在权限系统设计中的使用,因此也就不存在传统意义的数据库设计了。

    直接看类图

    在使用的时候只需这样

    User user=new User("E0001");
    if(user.hasPermissioin("R001001001")){
      //执行R001001001所代表的功能操作,例如“添加工单”的操作
    }

    一般的只需要User<->Role<->Resource即可,这里加入了一个ResourceList是为了使系统更加灵活,将系统的开发和实施分开。由开发人员管理Resource,由系统的实施人员进行RescourceList的创建,由用户的权限管理员管理角色及给角色赋予RescourceList。当系统有成千上万的资源时,这样做几乎是必须的。

    事情就这么解决了!不过还有一个问题,怎么管理需要进行权限验证的资源?难道每个都用 if(user.hasPermissioin("R001001001")) ?可以这么做,开发的时候对需要管控的程序部分写上 if(user.hasPermissioin("R001001001")) ,再在resources.xml文件中进行如下的配置。当上线的时候,实施人员也从resources.xml获取原始资源组成一个个许可权列表ResourceList。resources.xml可以非常简单

    <resources>
        <resource id="R001001001" name="添加工单"/>
        <resource id="R001001002" name="修改工单"/>
        ...
    </resources>

    这样做似乎也没什么问题,也不是太麻烦,只是程序中大量存在在if(user.hasPermissioin("R001001001")),并且还需要在resources.xml中填写资源名称,多了一层操作也就多了一个出错的可能,而且填写resources.xml似乎是一个比较傻瓜的事情,计算机就适合处理傻瓜的事情。

    和xml作为配置文件有相似功能的是注解(C#中称为特性),在不需要经常修改配置(只能由开发人员修改)的场合使用注解会比xml文件配置合适,XML 会导致配置和代码人为地隔开了,查看源代码了解映射关系会很不方便。这里的权限设计正好是这样,程序中添加资源必然后导致resources.xml的修改,resources.xml的修改肯定也说明程序有了改动,也就是这个配置必然是开发人员改动的,注解/特性就非常的合适。

    [Resource(Name="工单模块")]
    class WorkOrder{
    [Resource(Name
    ="创建工单")] public Create(){ } [Resource(Name="修改工单")] public Modify(){ } }

    系统中有哪些需要管理的资源?直接反射含特性的类和方法,资源的ID直接用类名+方法名即可。当前用户有没有权限访问这个操作资源,直接在Resource特性中进行过滤即可。这样程序的开发就是个很happy的事情了,要纳入权限管理的类或方法,就在上面加一句 [Resource(Name="")]

    如果系统非常庞大,又包含几个独立的子系统,那类似xml的配置文件可能还是少不了,需要灵活使用了。

    转载于:https://www.cnblogs.com/hashtag/p/4019122.html

    展开全文
  • /* *控制访问表 * acl值 功能 * 1 需要登录 * 2 自身修改 * 4 需要组的权限集合 * 8 需要身份访问集合 * 16 身份被禁止访问 * 32 可访问的日期 * 6
    <?php 
    /* 
    *控制访问表 
    *  acl值    功能 
    *    1        需要登录 
    *    2         自身修改 
    *    4         需要组的权限集合          
    *    8         需要身份访问集合     
    *    16         身份被禁止访问     
    *    32         可访问的日期     
    *    64         可访问的周日     
    *    128         可访问的时间     
    *    256         输入密码才能访问     
    *    512         超级管理使用     
    */ 
    class aclACL extends acl { 
        public $routername="acl"; 
        public $aclid='2';            //权限资源ID,如果登录人员没有拥用这个权限那么其(下面)它值都为0也不能访问 
        public $roledisable=array(9); //禁用身份 
        public $pwd=123456;           //密码访问 ACL->noPwd(); 
        public $date=array('begin'=>0,'end'=>0);   //允许日期之间 
        public $hours=array('begin'=>0,'end'=>0);  //一日内小时区间 
        public $weeks=array('begin'=>0,'end'=>0);  //一周内周一到周七 
        public $aclgroup=array("create"=>"4,45,8"); //create需要的组才能创建 
        public $aclrole=array("all"=>"6","create"=>"7,95,78"); //create需要的角色才能创建,该组需要ID为6的角色才能访问 
        public $acl=array("all"=>0, 
                          "index"=>4,    //表列4表示检查组的组合 
                          "delete"=>1,   //删除只登录后删除,当然呆以设置为2或4 
                          "update"=>1,   //更新提交只能登录后才能更新,在这里做也防止非法、post,edit是不能访问显示编辑内容页 
                          "createForm"=>1, //也不能新提交数据库 
                          "edit"=>0,       //登录才显示编辑框 
                          "show"=>0,       //不用登录也能显示 
                          "create"=>1);    //创新表单需要登录操作 可以设置某个组才能创建 
    
    }  
    
    ?>  

    这个是要认证的文件模块是acl
    每当用户访问acl模块时候,如果开启了认证那么会调用这个类
    然后这个类会根据$acl 的all或index等值去做认证检查。

    把这个文件放在router/acl目录里面就可以了,框架会自动认证如果用户没有相应的正向授权是无法访问相应的限制的。
    比如crud create方法 负向权限为17 那按照前面解释应该是 需要登录和组授权 就是$aclgroup 数组中create的4 45 8三个组,
    首先会员没有登录将提示登录,如果会员不在这三个组是无法访问该方法的会提示没有权限。

    目前router可以自己根据情况开启用acl控制
    方法是在xxxxRouter.class.php文件中 添加 public function isAcl(){}
    可以返回权限文件名比如返回curd,那么自动会调用curdACL.class.php类和名
    curdRouter类设置验证

    <?php 
    class curdRouter extends controller{ 
    
        //返回 RBAC 控制访问列表验证类默认是跟router同名也就是curd 
        //可以不写这个函数,那么不会启用通用权限系统。 
        public function isAcl(){}   
        public function index() 
        { 
           $booktype=M("booktype"); 
           $this->pager=C("pager");//取得分类 
           $this->pager->setPager($booktype->count(),10,'page');//取得数据总数中,设置每页为10 
           $this->assign("list",$booktype->orderby("bookid desc")->limit($this->pager->offset(),10)->fetch()->getRecord()); 
        } 
     public function login(){  //登录页面
    
      } 
      public function logout(){ //退出页面
    
          MY()->logout(); //退出登录
         redirect(url_for("guestbook/index"),"退出成功",3); 
      } 
      public function noAcl($mask) { //处理一下如果没有权限转向登录
          redirect(url_for("guestbook/login"),"需要登录",3); 
      } 
      public function loginpost() {  //登录提交地方 简单处理下登录认证
          if($_POST['author']=='queryphp'&&md5($_POST['pwd'])==md5('123456')) 
        { 
          MY()->setLogin(); //设置登录状态
          redirect(url_for("guestbook/adminlist"),"登录成功",3); 
        } 
        redirect(url_for("guestbook/login"),"登录失败",3); 
      }
    <?php
    /*
    *登录信息基本类
    *权限表可以缓存数据,登录时候恢复。
    */
     class mybase {
      public $options=array();
            public $uid;
      public $username;
      public $isadmin;
      public $role=array();  //我使用的身份
      public $group=array(); //我所在组
      public $grouprole=array(); //组的身份
      public $mygroupMar=array(); //我拥有管理的组
      public $mygroupOwn=array(); //属于我的组
      public $acl=array();       //主动控制表 groupacl和myacl控制权限集合 内容是rbac的rbacid
      public $groupacl=array();  //组拥用的控制权限
      public $myacl=array();     //我的身份拥用的控制权限
      public $loginfaild=0;      //登录失败次数 如果超过这个数应该禁止IP登录几分种

    这是基本
    可以把myUser.class.php放在项目lib目录里面

    <?php class myUser extends mybase { } ?>

    这里写图片描述

    这里写图片描述

    展开全文
  • 做了这么久的程序,但是权限的确是一个头痛的事情,于是乎,我们能不能做一个通用权限通用说得太绝对,能够用到80%我就心满意足了,好了废话不多说,我们由浅到深,足一说说。 文章一共有多少章张,这个我也说...

        做了这么久的程序,但是权限的确是一个头痛的事情,于是乎,我们能不能做一个通用的权限,通用说得太绝对,能够用到80%我就心满意足了,好了废话不多说,我们由浅到深,足一说说。

        文章一共有多少章张,这个我也说不清楚,说到什么地方,就什么地方吧。

    最简单的:分别有三张表,Users(用表)、Modules(模块表)、Roles(角色表)

     

    最后有SQL创建表或表数据的脚本,

     

    模块表数据:


    角色表数据:



    用户表数据:

    我们用admin 登录,获取它拥有的模块

    首先我们先获取它的角色,然后根据角色获取角色的模块:

    这里会出现一个用户存在多个角色的情况,所以查询语句需要改成



    然后获取到模块的编号了,然后我根据模块的编号去获取模块的信息,这里也得需要用到IN的方式去查询,而不能直接用等于:


    这样就得到了父级的模块了,我相信子级的,也不难了吧,查询语句如下

     

    View Code
    SELECT * FROM Modules 

    WHERE ParentID<>0 AND ModuleID IN(1,2,3,4,5,6)

    ORDER BY ModuleSrot ASC--这里是全部获取,但是这种不大有意义

     

    我们要获取父级的ModuleID然后在查询 

    View Code
    SELECT * FROM Modules 

    WHERE ParentID=(获取的ModuleID作查询条件) AND ModuleID IN(1,2,3,4,5,6)

    ORDER BY ModuleSrot ASC

     


    好,今天到此为止,下次继续,下次来中间表来做,查询的时候就简单多了,这种也有它一定的好处,这个就自己细细慢慢想想吧,下个给出数据的脚本:

    View Code
    ------------------------------------------------------------------------------表--------------------------------------------------------------------

    CREATE TABLE Users --用户表

    (

    UserID int identity(1,1) primary key not null, --用户编号

    UserName varchar(20) not null, --用户名

    Password varchar(50) not null, --用户密码

    RoleID varchar(50) not null, --角色编号(外键:Roles)

    )



    GO



    CREATE TABLE Modules

    (

    ModuleID int identity(1,1) primary key not null, --模块编号

    ModuleName varchar(50) not null, --模块名

    ParentID int DEFAULT(0) not null, --父编号

    LinkUrl varchar(200) null, --模块连接地址

    ModuleSrot int null, --模块的排序

    ModuleVisible bit DEFAULT(1) null, --模块是否现在

    --ParentID 为0时,表示顶级,比如“用户管理”ModuleID为1,下面的子级就为“添加用户”它的ParentID就为1

    --里面的字段要可以添加,不如图片地址什么的,这里就不写了

    )

    GO



    CREATE TABLE Roles --角色表

    (

    RoleID int identity(1,1) primary key not null, --角色编号

    RoleName varchar(20) not null, --角色名

    Descriptions varchar(50) not null, --角色描述

    Status int DEFAULT(1) not null, --状态

    ModuleID varchar(500) not null, --模块编号(外键:Modules)

    )



    GO





    --Users表中RoleID的值是roles的编号,存储值为:1,2,3多个角色,这里也可以用中间表来表示,这里就不举例了

    --Roles表中的ModuleID和Users表中RoleID的值差不多,

    ------------------------------------------------------------------------------表数据--------------------------------------------------------------------

    INSERT [Modules] ([ModuleID],[ModuleName],[ParentID],[ModuleSrot],[ModuleVisible]) VALUES ( 1,N'用户管理',0,1,1)

    INSERT [Modules] ([ModuleID],[ModuleName],[ParentID],[LinkUrl],[ModuleSrot],[ModuleVisible]) VALUES ( 2,N'添加用户',1,N'AddUser.aspx',1,1)

    INSERT [Modules] ([ModuleID],[ModuleName],[ParentID],[LinkUrl],[ModuleSrot],[ModuleVisible]) VALUES ( 3,N'用户列表',1,N'UserList.aspx',2,1)

    INSERT [Modules] ([ModuleID],[ModuleName],[ParentID],[ModuleSrot],[ModuleVisible]) VALUES ( 4,N'角色管理',0,2,1)

    INSERT [Modules] ([ModuleID],[ModuleName],[ParentID],[LinkUrl],[ModuleSrot],[ModuleVisible]) VALUES ( 5,N'添加角色',4,N'AddRole.aspx',1,1)

    INSERT [Modules] ([ModuleID],[ModuleName],[ParentID],[LinkUrl],[ModuleSrot],[ModuleVisible]) VALUES ( 6,N'角色列表',4,N'RoleList.aspx',2,1)


    go

    INSERT [Roles] ([RoleID],[RoleName],[Descriptions],[ModuleID]) VALUES ( 1,N'管理员',N'拥有所有权限',N'1,2,3,4,5,6')

    INSERT [Roles] ([RoleID],[RoleName],[Descriptions],[ModuleID]) VALUES ( 2,N'二级管理员',N'拥有用户管理权限',N'1,2,3')

    INSERT [Roles] ([RoleID],[RoleName],[Descriptions],[ModuleID]) VALUES ( 3,N'三级管理员',N'拥有角色管理权限',N'4,5,6')


    go

    INSERT [Users] ([UserID],[UserName],[Password],[RoleID]) VALUES ( 1,N'admin',N'123123',N'1')

    INSERT [Users] ([UserID],[UserName],[Password],[RoleID]) VALUES ( 2,N'admin1',N'123123',N'2')

    INSERT [Users] ([UserID],[UserName],[Password],[RoleID]) VALUES ( 3,N'admin2',N'123123',N'3')

    INSERT [Users] ([UserID],[UserName],[Password],[RoleID]) VALUES ( 4,N'admin3',N'123123',N'2,3')



    转载于:https://www.cnblogs.com/luxianai/archive/2012/03/16/Permission.html

    展开全文
  • 从第四章开始,我们将结合程序来实现权限的分配,和设计。 首先我们先用vs2011建立一个《web应用程序》程序,前期结构如下: 然后添加:实体、业务逻辑、和数据访问层的代码。这里我要说明一下,由于本人的习惯...

    今天我们讲解第四章,前三章,我们是通过数据库把所有用到的权限的数据库表都已经全部,该用到的视图也一并说明。从第四章开始,我们将结合程序来实现权限的分配,和设计。

       首先我们先用vs2011建立一个《web应用程序》程序,前期结构如下:


    然后添加:实体、业务逻辑、和数据访问层的代码。这里我要说明一下,由于本人的习惯,一般不会使用DataTableDataSet,所以我讲视图做完一张表,建立相应的实体、业务和数据访问层。搭建完成之后就开始正式编码了。 

    由于出于演示,代码编写不是很严格,界面不是很美观,请大家见谅! 

    首先是模块的问题:

             在一般的系统中,系统中的模块基本上是完全固定的,在程序编写完成之后,模块也就完成了,也就是说,数据库中的Modules表中的数据就不会发生什么变化了。所以,在我们系统第一次运行的时候,我们将所有的模块将保持到静态变量来保存,片段代码如下:

    首先声明一个静态变量来保持模块

    /// <summary>
    /// 保存系统所有模块
    /// </summary>
    public static List<Entity.ModuleInfo> objModuleList = new List<Entity.ModuleInfo>(); 
    
    //然后在Global.asax中加上这段代码
    
    void Application_Start(object sender, EventArgs e)
    {
        // 在应用程序启动时运行的代码,获取系统说有的模块
        if(Config.GlobalConfig.objModuleList == null || Config.GlobalConfig.objModuleList.Count<= 0)
        {
            Config.GlobalConfig.objModuleList= new BLL.ModuleBLL().GetModuleList();
        }
    }

     

    同样保存系统中的模块也可以用缓存来做,在这里,我就用这种方式来做,相对来说简单一点,这种也是一种缓存。

    在做完这些工作之后,我们现在来讲解系统登录,登录之后,我们首先要保登录用户的信息,这里我分别用了两种方式来保存,一种是cookie另一种是sessioncookie是保存用户编号,而session是保存整个用户对象(UserInfo),这里为什么需要用两种方式来保存了,可能是我庸人自扰了,因为我担心客户端可能禁用cookie的情况就是用session,但是session又极不稳定,所以我这里用到了两种情况。当然,我首先取值是从cookie里面取值的。

    片段代码如下:



     

    View Code
    /// <summary>
    /// 用户登录
    /// </summary>
    private void ValidataUser()
    {
        string userName = this.txtUserName.Text.Trim();
        string password = this.txtPassword.Text.Trim(); 
    
        UserInfo objInfo = new UserInfo();
        objInfo = newBLL.UserBLL().ValidataUser(userName,password);
    
        if(objInfo != null && objInfo.UserID >0)
        {
            //保存用户编号 (这里应该加密,但是我这里先省略)
            CookieHelper.SetCookie(GlobalConfig.CookieUserID,objInfo.UserID.ToString(), DateTime.Now.AddHours(1));
            //万一Cookie禁用,就用session
            Session[GlobalConfig.SessionUserInfo] = objInfo;
            //记住用户名
            if(this.RememberMe.Checked)
            {
                //设置保存用户名7天 (这里应该加密,但是我这里先省略)
                CookieHelper.SetCookie(GlobalConfig.RememberMe, userName, DateTime.Now.AddDays(7));
            }
            else
            {
                CookieHelper.Remove(GlobalConfig.RememberMe);
            }
    
            //登录成功跳转
            Response.Redirect("~/Default.aspx");
        }
        else
        {
            MessageBox.Show(this.Page, "用户名或密码错误!");
        }
    }

     

            

    登录完成之后,整体效果如下:

     

     

    现在来说说登录之后,模块的问题:

    首先当系统初次运行的时候,整个系统中的模块就已经获取了,现在我们做的就是根据用户的所属角色,获取用户的所属的模块。

     

    获取用户的模块片段代码如下:

            

    /// <summary>
    /// 根据登录用户角色编号,获取模块
    /// </summary>
    /// <paramname="roleId">角色编号</param>
    /// <returns>List</returns>
    private List<ModuleInfo> GetModuleList(string roleId)
    {
        List<int> objList = newList<int>();
        //根据用户编号,获取对应的模块编号
        objList = newBLL.RoleBLL().GetRoleIdByModuleID(roleId);
        List<ModuleInfo> objModuleList = new List<ModuleInfo>();
        foreach(var item inobjList)
        {
            //GlobalConfig.objModuleList获取相应的模块
            objModuleList.Add(GlobalConfig.objModuleList.Find(T => T.ModuleID== item));
        }
    
        if(objModuleList == null || objModuleList.Count<= 0)
            return null;
        return objModuleList;
    }

     

    系统中的模块详细都是从GlobalConfig.objModuleList变量中得到。

     

    登录完成之后,所有需要登录之后可以看到的页面,都继承BasePage类,此类中,有验证用户是否已经登录的相关验证,还有就是里面得到用户信息的相关变量。

    片段代码如下:

            

    View Code
    /// <summary>
    /// 用户编号
    /// </summary>
    public int UserID
    {
        get
        {
            UserInfo objInfo = new UserInfo();
            stringid = CookieHelper.GetCookie(GlobalConfig.CookieUserID);
            if(!string.IsNullOrEmpty(id))
            {
                objInfo = new BLL.UserBLL().GetUserEntity(Convert.ToInt32(id));
                return objInfo.UserID;
            }
            else
            {
                if(Session[GlobalConfig.SessionUserInfo] != null)
                {
                    objInfo = Session[GlobalConfig.SessionUserInfo] asUserInfo;
                    return objInfo.UserID;
                }
                else
                {
                    return 0;
                }
            }
        }
    } 
    
    /// <summary>
    /// 用户信息
    /// </summary>
    public UserInfo Users
    {
        get
        {
            if(this.UserID > 0)
            {
                return new BLL.UserBLL().GetUserEntity(this.UserID);
            }
            else
            {
                if(Session[GlobalConfig.SessionUserInfo] != null)
                {
                    return Session[GlobalConfig.SessionUserInfo]asUserInfo;
                }
                else
                {
                    return null;
                }
            }
        }
    }
    
    /// <summary>
    /// 角色名称
    /// </summary>
    public string RoleName
    {
        get
        {
            List<UserRoleInfo> objList = new List<UserRoleInfo>();
            objList = new BLL.UserRoleBLL().GetUserRoleList(this.UserID);
            if(objList == null || objList.Count <= 0)
                return null;
            string str = string.Empty;
            foreach(var item inobjList)
            {
                str += item.RoleName + ",";
            }
            returnstr.TrimEnd(',');
        }
    }

     

    由于基本的数据库查询,我都做了相对应的缓存,所以不必担心反复的读取数据库。 

    今天的编写先告一段落,一遍写这个文档,一遍写代码,实在是太难受了。由于代码完成量比较少,先不给大家源码了,等到下下章看看能不能给到大家源码,下章开始讲解 权限控件,预计拿两个章节来说,敬请期待! 

    最后献上四个不同角色的用户登录效果:

    Admin



     

    Admin1



     

    Admin2



     

    Admin3

    转载于:https://www.cnblogs.com/luxianai/archive/2012/04/01/tyqx4.html

    展开全文
  • 比如操作权限等等… 第五章,我们主要讲解权限控件,权限控件也就是自定义控件。如果你不明白自定义控件的话,你可以去网上查找相关资料,我这里不做详细的讲解。 说到自定义权限控件,我们这里将会想到权限跟...
  • 记得上次写这系列文章的时候,还在是一个月之前,今天我们继续讲解。...首先我们得建立三张表,一张“权限表(Permissions)”,一张中间表“模块权限表(ModulePermissions)”和一张角色权限表(RolePermissions)...
  • 这章紧接着第五章的内容,如果你没有看过第五章的...第五章我们得到了用户所属模块的权限,这一步至关重要,也是这权限控件的灵魂。 现在进入今天的主题,添加一个类,命名为:PDButton,PD是我自己加的前缀,与C#...
  • 第一章我们说了权限,地址为:http://www.cnblogs.com/luxianai/archive/2012/03/16/Permission.html,但是没有用到中间表,今天我们来说说使用中间来做,这样查询将会更加方便,具体如下: 分别有五张表,Users...
  • 大家好, 我目前做了一个通用权限系统 也想跟大家讨论下 我的通用权限系统设计是更换权限时候尽量不要涉及到代码修改 这个是要认证的文件模块是acl 每当用户访问acl模块时候,如果开启了...
  • 今天暂时就看权限管理系统的数据库表设计吧。子系统表,因为我这里设计的为了能够集成公司内部以后所有的系统的,所以建了子系统这张表,如果单个项目,这张表可以去掉。模块表,系统中的各个模块。模块功能表,模块...
  • 通用权限管理系统设计通用权限管理系统设计
  • 通用角色权限管理系统设计

    千次下载 热门讨论 2012-05-01 17:25:48
    通用角色权限管理系统设计 因为做过的一些系统的权限管理的功能虽然在逐步完善,但总有些不尽人意的地方,总想抽个时间来更好的思考一下权限系统的设计。 权限系统一直以来是我们应用系统不可缺少的一个部分,若每...
  • 1.2 要素分析2 数据权限设计2.1 规则元2.2 规则元配置2.3 数据规则的配置2.4 数据规则的解析2.5 确定当前查询适用的数据规则 1 数据权限概述 1.1 什么是数据权限? 数据权限是指对系统用户进行数据资源可见性的控制...
  • 权限控制论文,介绍权限控制在系统设计时的应用
  • 通用数据权限管理系统设计

    千次阅读 2018-03-08 15:33:38
    通用数据权限管理系统设计(一) 作者:逸云 前言: 本文提供一种集成功能权限和数据权限的解决方法,以满足多层次组织中权限管理方面的集中控制。本方法是RBAC(基于角色的访问控制方法)的进一步扩展和延伸,即...
  • 权限管理系统通用设计
  • 权限管理对于每个Web应用都有其相似、相近的地方,文章在Java EE平台上设计了基于角色分配的通用权限管理系统,其它应用可以很容易地在其基础上进行开发,从而缩短项目的开发周期。
  • 通用权限系统

    2012-10-13 10:41:57
    java 通用权限设计,分用户,角色,权限,资源,操作
  • 通用权限系统数据库设计,ORCLA 数据库的教学项目

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,902
精华内容 760
关键字:

通用权限系统设计