权限管理系统设计方案

前言:权限设计是一个80%的程序员都会遇到的问题,比如应用系统权限,数据库的访问权限,公文流转中的审批权限,操作系统中文件的访问权限,公司内部单据的审批权限,政府机构的上下级权限等,在现实生活中,权限无处不在,无时不有。这里要介绍的是关于文档的访问权限的一种设计方案,供大家讨论,希望能起到抛砖引玉的作用。
       在公司内部,合同文件,针对某一个客户的设计草案等一系列物理的文件,组成了一个逻辑上的文档,典型的如应用系统设计中数据库设计ER图、类图、对象图等一系列的文件,在逻辑上可以称之为一个应用系统的设计文档。当类似的文档超过几百个之后,公司内部文档的管理依靠建立纸质的文档卡片来检索文件便显得比较慢了,这时一个在线的文档管理系统就成为公司这个阶段的需求,用于解决文档过多带来的诸多不便。
       在线文档管理系统的主要目标就是方便用户管理文档和互相交流,但并不是每个人都可以对任何文档查看或者修改。权限管理在这里便成为举足轻重的问题:那些是我的文档,同部门的同事对我的文档具有哪些权限,其他人对我的文档有哪些权限,其他部门的人对我的文档有什么权限,是否可以有一个特定的人或者特定的部门对我的文档有特定的权限。本文针对这些问题提供一个解决方案,其中一些必须的元素比如,用户的设计,部门的设计不在本文讨论之列,假设您已经设计的比较完善。笔者借鉴UNIX的一些权限设计的思想来讨论和解决这些问题。分两部分:
第一部分讨论权限的种类:针对每个文档,需要填写以下文档信息,比如文档的名称,作者等,之后添加附件。对于文档的操作固定分为4种:下载,删除,修改,查看。比如需要下载某个文件,就需要具备下载权限,但首先要具备查看的权限,如果没有查看权限,则就无从下载,如果需要修改某些信息,包括重新上传文件,则需要具备修改的权限。这4中权限可以使用四个位来代替,1代表有权限,0带便没有权限,比如第一个位为下载,第二个为删除,第三个位为修改,第四个位为查看,则1111就具备了所有的权限,0000则表示没有任何权限,这样的二进制位便可以以16进制的方式存储在数据库中比如使用0..A..F则在数据库中的存储只为一个字节。如果需要添加权限,那么在高位添加这个权限。Java中的Integer类中可以方便的进行移位操作,针对给出的权限的二进制位,在相应位进行&操作,判断结果是否大于0就知道是否有权限,比如1010与0010进行&操作,如果结果大于0,则说明有修改的权限。如果需要增加权限,则把原来的权限取出来,在相应的权限位进行或|运算,之后再存进去。这点和Unix的权限设计一致。
第二部分讨论如何授权,假设用户具备一个唯一的×××ID号,每个部门具备一个×××ID号,对于具有1000人的公司来说,部门有上百个,他们的平均ID号的长度可以假设为3位。在文档的记录中需要添加一个字段填写文档拥有者的编号(owner),以便于标示这个文档属于谁的。同时也添加拥有者所在的部门编号(dept),如果同一个人曾经在两个部门工作过,那么他在不同时期的文档应该属于不同的部门。在这些之后需要有一个文档拥有者的权限字段(ownerAuth),存储1个字节的权限信息(假设只有四种权限)。同部门的人经常需要查看,或者修改等操作,为了方便检索需要添加同部门权限(deptAuth),同样是1个字节,也要有其他任何人对该文档的权限(otherAuth),假设是一个通知,或者文档的模板,需要所有人具备读权限,使用这个方式就比较合适。如果需要对某个人授权怎么办?如果对某个部门单独授权怎么办?这里有两种方案,1.添加一个表,与文档表是多对一的关系,这样就可以把一个文档授权给多个部门,或者多个人。2.添加两个字段,usersAuth,deptsAuth,注意,auth之前有个s,表示存储多个人或者部门的权限。存储的内容为ID号加权限,比如usersAuth中的100:f,101:A,表示ID号为100的用户有用F所有的权限,以此类推,可知为单个人或者部门授权需要6个字节,1k个字段长度已经可以对170多个对象单独授权,这基本上是一个操作人员的极限,操作人员不会闲的无聊把一个对象逐个的授权给170个人或者部门,属于小概率事件,实际中可以忽略不计。这两种方案中,作者偏向于第二种,优点是查询次数少,其缺点是授权对象个数有限制。如何判断一个用户对某一个文档是否有特定的权限,在这里可以根据自己的使用情况定一个优先查找顺序,比如要判断用户对文档A是否有读的权限,则可以从ownerAuth->groupAuth->otherAuth->usersAuth->deptsAuth的优先顺序查找判断,也可以按照自己的方案判断,对于otherAuth比较常用的文档系统,把otherAuth的权限判断放在第一位也许更合适。这个没有统一的准则。
以上是作者对文档权限设计的一点想法,时间仓促,没有仔细琢磨语句是否通畅,如果有说的不清楚的地方或者有不正确的地方,欢迎指教。
-----------------------------------
 https://blog.51cto.com/tianli/227217

系统权限(System Authority)= 功能权限+数据权限

一、为什么需要权限管理

        日常工作中权限的问题时时刻刻伴随着我们,程序员新入职一家公司需要找人开通各种权限,比如网络连接的权限、编码下载提交的权限、监控平台登录的权限、运营平台查数据的权限等等。

在很多时候我们会觉得这么多繁杂的申请给工作带来不便,并且如果突然想要查一些数据,发现没有申请过权限,需要再走审批流程,时间拉得会很长。那为什么还需要这么严格的权限管理呢?

举个例子,一家支付公司有运营后台,运营后台可以查到所有的商户信息,法人代表信息,交易信息以及费率配置信息,如果我们把这些信息不加筛选都给到公司的每一个小伙伴,那么跑市场的都可以操作商家的费率信息,如果一个不小心把费率改了会造成巨大的损失。

又比如商户的信息都是非常隐秘的,有些居心不良的小伙伴把这些信息拿出来卖给商家的竞争对手,会给商家造成严重的不良后果。虽然这么做都是个别人人为的过错,但是制度上如果本身这些信息不开放出来就能在很大程度上避免违法乱纪的事情发生了。

总体来讲**权限管理是公司数据安全的重要保证,针对不同的岗位,不同的级别看到的数据是不一样的,操作数据的限制也是不一样的。**比如涉及到资金的信息只开放给财务的相关岗位,涉及到配置的信息只开放给运营的相关岗位,这样各司其职能避免很多不必要的安全问题。

2.1 权限设计

        从业务分类上来讲权限可以分为数据查看权限,数据修改权限等,对应到系统设计中有页面权限、菜单权限、按钮权限等。菜单也分一级菜单、二级菜单甚至三级菜单,以csdn文章编辑页面左侧菜单栏为例是分了两级菜单。菜单对应的页面里又有很多按钮,我们在设计的时候最好把权限设计成树形结构,这样在申请权限的时候就可以一目了然的看到菜单的结构,需要哪些权限就非常的明了了

2.2 为什么需要角色

        权限结构梳理清晰之后,需要思考怎么把权限分配给用户,用户少的情况下,可以直接分配,一个用户可以有多个权限,统一一个权限可以被多个用户拥有,用户-权限的模型结构如下所示:

         这种模型能够满足权限的基本分配能力,但是随着用户数量的增长,这种模型的弊端就凸显出来了,每一个用户都需要去分配权限,非常的浪费管理员的时间和精力,并且用户和权限杂乱的对应关系会给后期带来巨大的维护成本。用户-权限对应关系图:

        这种对应关系在用户多的情况下基本无法维护了。其实很多用户负责同一个业务模块所需要的权限是一样的,这样的话我们是不是可以借助第三个媒介,把需要相同的权限都分配给这个媒介,然后用户和媒介关联起来,用户就拥有了媒介的权限了。这就是经典的RBAC模型,其中媒介就是我们通常所说的角色。

2.3 权限模型的演进

1 基本的RBAC模型

        有了角色之后可以把权限分配给角色,需要相同权限的用户和角色对应起来就可以了,一个权限可以分配给多个角色,一个角色可以拥有多个权限,同样一个用户可以分配多个角色,一个角色也可以对应多个用户,对应模型如下所示:

        这就是经典的RBAC模型(role-based-access-control),在这里面角色起到了桥梁左右,连接了用户和权限的关系,每个角色可以拥有多个权限,每个用户可以分配多个角色,这样用户就拥有了多个角色的多个权限。

同时因为有角色作为媒介,大大降低了错综复杂的交互关系,比如一家有上万人的公司,角色可能只需要几百个就搞定了,因为很多用户需要的权限是一样的,分配一样的角色就可以了。这种模型的对应关系图如下所示:

         用户和角色,角色和权限都是多对多的关系,这种模型是最通用的权限管理模型,节省了很大的权限维护成本, 但是实际的业务千变万化,权限管理的模型也需要根据不同的业务模型适当的调整,比如一个公司内部的组织架构是分层级的,层级越高权限越大,因为层级高的人不仅要拥有自己下属拥有的权限,二期还要有一些额外的权限。

RBAC模型可以给不同层级的人分配不同的角色,层级高的对应角色的权限就多,这样的处理方式可以解决问题,但是有没有更好的解决办法呢,答案肯定是有的,这就引出角色继承的RBAC模型

2.4 引入用户组的RBAC模型、角色限制的RBAC模型

2.4.1 用户组

        我们创建角色是为了解决用户数量大的情况下,用户分配权限繁琐以及用户-权限关系维护成本高的问题。抽象出一个角色,把需要一起操作的权限分配给这个角色,把角色赋予用户,用户就拥有了角色上的权限,这样避免了一个个的给用户分配权限,节省了大量的资源。

        同样的如果有一批用户需要相同的角色,我们也需要一个个的给用户分配角色,比如一个公司的客服部门有500多个人,有一天研发部研发了一套查询后台数据的产品,客服的小伙伴都需要使用,但是客服由于之前并没有统一的一个角色给到所有的客服小伙伴,这时候需要新加一个角色,把权限分配给该角色,然后再把角色一个个分配给客服人员,这时候会发现给500个用户一个个添加角色非常的麻烦。但是客服人员又有共同的属性,所以我们可以创建一个用户组,所有的客服人员都属于客服用户组,把角色分配给客服用户组,这个用户组下面的所有用户就拥有了需要的权限。

RBAC模型添加用户组之后的模型图如下所示:

        很多朋友会问,用户组和角色有什么区别呢?简单的来说,用户组是一群用户的组合,而角色是用户和权限之间的桥梁。 用户组把相同属性的用户组合起来,比如同一个项目的开发、产品、测试可以是一个用户组,同一个部门的相同职位的员工可以是一个用户组, 一个用户组可以是一个职级,可以是一个部门,可以是一起做事情的来自不同岗位的人。

用户可以分组,权限也可以分组,权限特别多的情况下,可以把一个模块的权限组合起来成为一个权限组,权限组也是解决权限和角色对应关系复杂的问题。

比如我们定义权限的时候一级菜单、二级菜单、按钮都可以是权限,一个一级菜单下面有几十个二级菜单,每个二级菜单下面又有几十个按钮,这时候我们把权限一个个分配给角色也是非常麻烦的,可以采用分组的方法把权限分组,然后把分好的组赋予角色就可以了。

给权限分组也是个技术活,需要理清楚权限之间的关系,比如支付的运营后台我们需要查各种信息,账务的数据、订单的数据、商户的数据等等,这些查询的数据并不在一个页面,每个页面也有很多按钮,我们可以把这几个页面以及按钮对应的权限组合成一个权限组赋予角色。加入权限组之后的RBAC模型如下所示:

三、模型设计:RBAC(Role-Based Access Control)

通用的“用户角色权限”平台设计 - 知乎

        RBAC(基于角色的访问控制)是指用户通过角色与权限进行关联。即一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户—角色—权限”的授权模型。在这种模型中,用户与角色之间、角色与权限之间,一般者是多对多的关系。

2.1 账号表(account)

        在我们的系统中,会有各种各样的登录方式,如手机号、邮箱地址、身份证号码和微信登录等。因此该表主要是用来记录每一种登录方式的信息,但不包含密码信息,因为各种登录方式都会使用同一个密码。每一条记录都会关联到唯一的一条用户记录。

账号表(account):只存储账号相关信息(如密码、注册来源、注册 IP,但不包括登录账号)

CREATE TABLE `account`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '账号ID',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
  `open_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '登录账号,如手机号等',
  `category` tinyint(1) NULL DEFAULT NULL COMMENT '账号类别',
  `created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `edited` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `editor` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `deleted` double(1, 0) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '逻辑删除:0=未删除,1=已删除',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_member_id`(`user_id`) USING BTREE COMMENT '普通索引',
  CONSTRAINT `account_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
)

2.2 用户表(user)

        主要是用来记录用户的基本信息和密码信息。其中禁用状态(state)主要是在后台管理控制非法用户使用系统;密码加盐(salt)则是用于给每个用户的登录密码加一把唯一的锁,即使公司加密公钥泄露后,也不会导致全部用户的密码泄露。

用户信息表(user):只存储用户基本信息(不包括密码)

CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `state` tinyint(1) NULL DEFAULT NULL COMMENT '用户状态:0=正常,1=禁用',
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名',
  `head_img_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像图片地址',
  `mobile` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号码',
  `salt` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码加盐',
  `password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '登录密码',
  `created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `edited` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `editor` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `deleted` tinyint(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '逻辑删除:0=未删除,1=已删除',
  PRIMARY KEY (`id`) USING BTREE
) 

 2.3 权限表(permission)

有了用户之后,我们希望不同的用户能操作和查看不同的功能(如页面、菜单和按钮等)。因此需要定义一张表来存储权限相关的信息。包括权限之前还有父子关系,分配了父级后,应该拥有所有的子级权限。同时权限的信息也会分配至前端页面来控制,因此需要提供一个唯一标识(code),有人会问 id 不行吗?当然可以,只是我们的 ID 是自动生成,每个环境都不一样,重新生成后也不一样,因此才单独使用了一个字段来标识。

CREATE TABLE `permission`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '权限ID',
  `parent_id` bigint(20) NULL DEFAULT NULL COMMENT '所属父级权限ID',
  `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限唯一CODE代码',
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限名称',
  `intro` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限介绍',
  `category` tinyint(1) NULL DEFAULT NULL COMMENT '权限类别',
  `uri` bigint(20) NULL DEFAULT NULL COMMENT 'URL规则',
  `created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `edited` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `editor` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `deleted` tinyint(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '逻辑删除:0=未删除,1=已删除',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `parent_id`(`parent_id`) USING BTREE COMMENT '父级权限ID',
  INDEX `code`(`code`) USING BTREE COMMENT '权限CODE代码'
)

2.4 角色表(role)

为了解决维护起来方便,我们会对权限表中的记录进行分组,将相关的一些权限分配为同一组,称之为角色。角色表的作用是为了将零散的权限进行聚合,然后方便对相关的一组进行统一处理(即小范围批量处理)。该表的增加可谓是大大减少了上述维护困难的问题。

CREATE TABLE `role`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
  `parent_id` bigint(20) NULL DEFAULT NULL COMMENT '所属父级角色ID',
  `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色唯一CODE代码',
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名称',
  `intro` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色介绍',
  `created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `edited` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `editor` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `deleted` tinyint(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '逻辑删除:0=未删除,1=已删除',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `parent_id`(`parent_id`) USING BTREE COMMENT '父级权限ID',
  INDEX `code`(`code`) USING BTREE COMMENT '权限CODE代码'
) 

 2.5 用户—角色表(user_role)

该表主要是用来存储每个用户拥有哪些角色。一般情况,每个用户只会有几个角色,因此数据量从 100 亿变成 10 亿或更少。

CREATE TABLE `user_role`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
  `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
  `created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `edited` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `editor` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `deleted` tinyint(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '逻辑删除:0=未删除,1=已删除',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `member_id`(`user_id`) USING BTREE COMMENT '用户ID',
  INDEX `role_id`(`role_id`) USING BTREE COMMENT '角色ID',
  CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
)

2.6 角色 - 权限表(role_permission)

该表则是用来定义每个角色组中有哪些权限。该表的数量则更少(基本都在 1 万条以内)。

CREATE TABLE `role_permission`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
  `permission_id` bigint(20) NULL DEFAULT NULL COMMENT '权限ID',
  `created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `edited` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `editor` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `deleted` tinyint(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '逻辑删除:0=未删除,1=已删除',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `role_id`(`role_id`) USING BTREE COMMENT '角色ID',
  INDEX `permission_id`(`permission_id`) USING BTREE COMMENT '权限ID',
  CONSTRAINT `role_permission_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `role_permission_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permission` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
)

3.1 用户组表(user_group)

上述虽然增加了角色表(role)后,把数据量从 100 亿降低至 10 亿,但 10 倍的数据量依然还是很多。而且大部分的用户(主体用户。如学生系统,学生就是主体)都会分配相同的角色组。用户组和角色组的区别:

  • 角色组(role):解决的是权限的分组,减少了权限的重复分配
  • 用户组(user_group):解决的是用户的分组,减少了用户的重复授权
CREATE TABLE `user_group`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `parent_id` bigint(20) NULL DEFAULT NULL COMMENT '所属父级用户组ID',
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户组名称',
  `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户组CODE唯一代码',
  `intro` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户组介绍',
  `created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `edited` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `editor` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `deleted` tinyint(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '逻辑删除:0=未删除,1=已删除',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `parent_id`(`parent_id`) USING BTREE COMMENT '父级用户组ID',
  INDEX `code`(`code`) USING BTREE COMMENT '用户组CODE代码'
) 

 3.2 用户组—用户表(user_group_user)

该表用来记录每个用户组下有哪些用户。

CREATE TABLE `user_group_user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID说',
  `user_group_id` bigint(20) NULL DEFAULT NULL COMMENT '用户组ID',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
  `created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `edited` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `editor` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `deleted` tinyint(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '逻辑删除:0=未删除,1=已删除',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `member_group_id`(`user_group_id`) USING BTREE COMMENT '用户组ID',
  INDEX `member_id`(`user_id`) USING BTREE COMMENT '用户ID',
  CONSTRAINT `user_group_user_ibfk_1` FOREIGN KEY (`user_group_id`) REFERENCES `user_group` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `user_group_user_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) 

3.3 用户组—角色表(user_group_role)

该表用来记录每个用户组下拥有哪些用户角色。

CREATE TABLE `user_group_role`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `user_group_id` bigint(20) NULL DEFAULT NULL COMMENT '用户组ID',
  `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
  `created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `edited` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `editor` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `deleted` tinyint(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '逻辑删除:0=未删除,1=已删除',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `member_group_id`(`user_group_id`) USING BTREE COMMENT '用户组ID',
  INDEX `role_id`(`role_id`) USING BTREE COMMENT '角色ID',
  CONSTRAINT `user_group_role_ibfk_1` FOREIGN KEY (`user_group_id`) REFERENCES `user_group` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `user_group_role_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) 

        每个系统主体用户,基本都占用了所有用户的 90% 以上(既包含用户,又包含商家的系统,用户和商家同时都是主题用户)。因此,每个用户注册时,基本只需要分配一条所属的用户组,即可完成角色权限的配置。这样处理后,数据量将从 10 亿下降至 1 亿多。同时也减少了用户注册时的需批量写入数量。

 用户表(t_user)
用户组表(t_group)
角色表(t_role)
权限表(t_permission)
用户表-用户组(user_group)
用户—角色表(user_role) 
用户组—角色表(group_role)
角色-权限表(role_permission)

三、Django:用户认证、权限管理

         权限是能够约束用户行为和控制页面显示内容的一种机制。一个完整的权限应该包含用户,对象和权限3个要素,即什么用户对什么对象有什么样的权限。

Django自带的权限机制仅针对模型,即一个用户如果对Article模型有change权限,那么该用户对所有文章都有修改权限。如果实现对单个对象的权限管理,可以借助于第三方库guardian。本文将从分别从自带的“auth模块”权限机制和guardian展开介绍。

一、 自带权限机制

auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组和权限管理。

1.1表结构

与 auth 模块有关的数据库表有 6 张,分别是

项目

作用

备注

auth_user.

用户信息

auth_group

组信息

每个组拥有id和name两个字段

auth_user_groups

user和group之间的关系

auth_user_user_permissions

user和prmission之间的关系

auth_permission

权限

每条权限拥有id ,name , 

content_type_id, codename四个字段

auth_group_permissions

用户组和权限的对应关系

使用用户组管理权限是一个更方便的方法,Group中包含多对多字段permissions

1.1 auth_user

auth_user 表维护了用户信息,结构如下:

CREATE TABLE `auth_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `password` varchar(128) COLLATE utf8mb4_unicode_ci NOT NULL,
  `last_login` datetime(6) DEFAULT NULL,
  `is_superuser` tinyint(1) NOT NULL,
  `username` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL,
  `first_name` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
  `last_name` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(254) COLLATE utf8mb4_unicode_ci NOT NULL,
  `is_staff` tinyint(1) NOT NULL,
  `is_active` tinyint(1) NOT NULL,
  `date_joined` datetime(6) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

1.2 auth_group  

auth_group 表只有 id 和 name 两个字段,结构如下:

CREATE TABLE `auth_group` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

通过 auth_user_groups 表, auth_group 和 auth_user 之间建立了一个多对多的关系,结构如下:

auth_user_groups

CREATE TABLE `auth_user_groups` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `group_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `auth_user_groups_user_id_group_id_94350c0c_uniq` (`user_id`,`group_id`),
  KEY `auth_user_groups_group_id_97559544_fk_auth_group_id` (`group_id`),
  CONSTRAINT `auth_user_groups_group_id_97559544_fk_auth_group_id` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
  CONSTRAINT `auth_user_groups_user_id_6a12ed8b_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

1.3 auth_permission:表储存了对 model 的权限信息。

CREATE TABLE `auth_permission` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `content_type_id` int(11) NOT NULL,
  `codename` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `auth_permission_content_type_id_codename_01ab375a_uniq` (`content_type_id`,`codename`),
  CONSTRAINT `auth_permission_content_type_id_2f476e4b_fk_django_co` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

auth_group_permissions

维护了 auth_permission 和 auth_group 之间多对多的关系

CREATE TABLE `auth_group_permissions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `group_id` int(11) NOT NULL,
  `permission_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `auth_group_permissions_group_id_permission_id_0cd325b0_uniq` (`group_id`,`permission_id`),
  KEY `auth_group_permissio_permission_id_84c5c92e_fk_auth_perm` (`permission_id`),
  CONSTRAINT `auth_group_permissio_permission_id_84c5c92e_fk_auth_perm` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`),
  CONSTRAINT `auth_group_permissions_group_id_b120cbf9_fk_auth_group_id` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

auth_user_user_permissions

维护了 auth_permission 和 auth_user 之间多对多的关系

CREATE TABLE `auth_user_user_permissions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `permission_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `auth_user_user_permissions_user_id_permission_id_14a6b632_uniq` (`user_id`,`permission_id`),
  KEY `auth_user_user_permi_permission_id_1fbb5f2c_fk_auth_perm` (`permission_id`),
  CONSTRAINT `auth_user_user_permi_permission_id_1fbb5f2c_fk_auth_perm` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`),
  CONSTRAINT `auth_user_user_permissions_user_id_a95ead1b_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

以上三张表保证了auth 模块到model级别的权限管理,即用户是否对某个数据表拥有增(add), 改(change), 删(delete)权限。

如果需要对象级权限管理,需要使用第三方库,比如 django-guardian 。

注:auth_permission 表中的 content_type_id 项是 django.contrib.contenttypes 模块的应用。

二、相关方法和函数

  • authenticate(),用户认证。如果认证信息有效,会返回一个 User 对象。无效返回None
  • user.set_password(new_password),修改用户密码
  • login(HttpRequest, user),结合 django.contrib.sessions 模块,给已认证的用户附加上session id等信息。
  • logout(request),注销用户
  • @login_required 修饰器,会先通过 session key 检查是否登录, 已登录用户可以正常的执行操作, 未登录用户将被重定向到 login_url 指定的位置。若未指定 login_url 参数, 则重定向到settings.LOGIN_URL
  • user.has_perm, 检查用户是否拥有操作某个模型的权限:
user.has_perm('blog.add_article')
user.has_perm('blog.change_article')
user.has_perm('blog.delete_article')
  • django.contrib.auth.middleware.AuthenticationMiddleware,添加currently-logged-in user 到 HttpRequest对象的user属性。
  • django.contrib.auth.context_processors.auth将 auth 添加到 template 的上下文中(context)
  • django.contrib.auth.password_validation中提供了 一系列的密码强度校验。

注意:这个检验只针对命令行操作 createsuperuserchangepassword等 ,对 model 的操作,比如 User.objects.create_user()create_superuser()等无效(因为这些是开发者的操作,而不是用户的操作)

猜你喜欢

转载自blog.csdn.net/qq_22473611/article/details/126334276