Java生鲜电商平台-RBAC系统权限的设计与架构数据库
说明:根据上面的需求描述以及对需求的分析,咱们得知一般的一个中小型系统对于权限系统所需实现的功能以及非功能性的需求,在下面咱们将根据需求从技术角度上分析实现的策略以及基于目前两种比较流行的权限设计思想来讨论关于权限系统的实现。缓存
1.1. 技术策略安全
l 身份认证服务器
在B/S的系统中,为识别用户身份,一般使用的技术策略为将用户的身份记录在Session中,也就是当用户登陆时即获取用户的身份信息,并将其记录到Session里,当须要进行身份认证的时候经过从Session中获取用户的身份信息来实现用户的身份认证。session
l 资源权限校验架构
资源权限校验取决于系统的受权模型,这块将在以后进行详细的阐述。框架
l 数据权限校验性能
数据权限校验取决于系统的受权模型,这块将在以后进行详细的阐述。网站
l 受权模型编码
受权模型做为权限系统的核心,从本质上决定了权限系统的易用性,这个易用性包括权限的授予和权限的校验,并同时也决定了权限的继承,权限的排斥和包含等方面的实现。
在经历了这么多年的发展,受权模型在目前中小型应用系统接受的比较多的主要有RBAC模型和ACL模型,将在以后展开专门的篇幅进行讲解。
l 权限校验的体现
权限校验的体如今中小型系统中体现出来的一般只是对于系统菜单、按钮显示的控制和对于拥有权限的数据的访问上。
它们共同依赖于资源权限校验和数据权限校验,对于系统菜单、按钮的显示上的控制在B/S中一般采用的技术策略为在生成菜单、按钮的Html时作权限级的判断,当操做主体不具有权限时则不生成该菜单、按钮的Html,从技术角度分析为方便使用者,避免使用者调用权限校验接口,一般的作法为提供菜单、按钮的标签,经过此标签生成的菜单和按钮即为通过权限过滤的。
l 高性能
为提升权限系统在受权以及校验权限时的性能,一般的作法为采用缓存技术以及增强权限系统的管理建设,增强权限系统的管理建设有助于创建一个最为适合需求的权限结构,同时作到了简化系统权限授予。
l 安全性
安全性方面来说在B/S系统中一般有两个方面须要控制:
n 经过非法途径访问系统文件
在Java的Web应用中一般采用的技术策略为将须要受保护的文件放入WEB-INF文件夹中,你们都知道在WEB-INF下的文件除了在服务器上能直接访问外,经过普通的URL是没法访问到的。
其次的作法为作Filter,即对须要受保护的资源作访问的Filter,如操做者不具有权限则直接报出错误。
n 经过非法途径访问系统操做
一般采用的技术策略为对每一个直接暴露对外的须要授权限保护的对象作操做级别的权限控制,简单来讲在Web系统中一般采用MVC框架来实现,一般Command层是直接对外的,为防止用户经过URL或其余方式访问Command,从技术上咱们须要考虑对现有系统的尽可能少的侵入性,因此一般采用的作法是在Command之上作Before Interceptor或Proxy,在此Interceptor或Proxy中作权限的校验,以确认操做者具备相应的权限。
通过上面的描述,咱们已经基本了解到知足权限系统需求的技术实现策略,从中咱们也能够看出权限系统中最为重要的为受权模型,因为权限系统的通用性,在业界也是推出了很多的受权模型,在这里咱们已目前比较通用的两种受权模型来具体讲解权限系统的完整实现。
1.2. 基于RBAC的实现
1.2.1. RBAC介绍
RBAC模型做为目前最为普遍接受的权限模型,在此也将对其模型进行简要的介绍,RBAC模型成功的经典应用案例当属Unix系统了。
NIST(The National Institute of Standards and Technology,美国国家标准与技术研究院)标准RBAC模型由4个部件模型组成,这4个部件模型分别是基本模型RBAC0(Core RBAC)、角色分级模型RBAC1(Hierarchal RBAC)、角色限制模型RBAC2(Constraint RBAC)和统一模型RBAC3(Combines RBAC)[1]。RBAC0模型如图1所示。
图表 1 RBAC 0模型
l RBAC0定义了能构成一个RBAC控制系统的最小的元素集合
在RBAC之中,包含用户users(USERS)、角色roles(ROLES)、目标objects(OBS)、操做operations(OPS)、许可权permissions(PRMS)五个基本数据元素,权限被赋予角色,而不是用户,当一个角色被指定给一个用户时,此用户就拥有了该角色所包含的权限。会话sessions是用户与激活的角色集合之间的映射。RBAC0与传统访问控制的差异在于增长一层间接性带来了灵活性,RBAC一、RBAC二、RBAC3都是前后在RBAC0上的扩展。
l RBAC1引入角色间的继承关系
角色间的继承关系可分为通常继承关系和受限继承关系。通常继承关系仅要求角色继承关系是一个绝对偏序关系,容许角色间的多继承。而受限继承关系则进一步要求角色继承关系是一个树结构。
l RBAC2模型中添加了责任分离关系
RBAC2的约束规定了权限被赋予角色时,或角色被赋予用户时,以及当用户在某一时刻激活一个角色时所应遵循的强制性规则。责任分离包括静态责任分离和动态责任分离。约束与用户-角色-权限关系一块儿决定了RBAC2模型中用户的访问许可。
l RBAC3包含了RBAC1和RBAC2
既提供了角色间的继承关系,又提供了责任分离关系。
1.2.2. 实现方案
经过上面章节对RBAC的介绍,从RBAC模型中咱们能够看出它已经实现了一个使用起来很方便的受权模型,并同时也就权限的继承,权限的排斥和包含提出了解决的模型。
那么如今的关键是咱们须要来看看基于RBAC究竟是怎么实现权限系统的需求的呢?在这里咱们针对在技术策略中未描述的受权模型和权限校验部分作实现方案的讲解。
l 受权模型
受权模型遵循RBAC进行搭建,即创建如上图表一的模型。
针对受权模型中的几个关键部分咱们进行描述:
n 受权
按照RBAC的模型,在受权时分为配置资源以及资源的操做、授予角色对资源的操做权限、分配角色给用户这几个步骤来完成。
从这几个步骤咱们进行分析:
u 配置资源以及资源的操做
实现这步很是的简单,直接维护资源以及资源操做两个对象的持久便可实现。
u 授予角色对资源的操做权限
实现这步一样很是的简单,维护角色与资源的关联模型便可。
u 分配角色给用户
实现这步一样很是的简单,维护角色与用户的关联模型便可。
n 权限的继承
权限的继承在RBAC的模型中经过增长角色的自关联来实现,即角色可拥有子角色,子角色继承父角色的权限。
按照此模型能够看出在受权时维护权限的继承也是很是的简单,维护角色的自关联模型便可。
n 权限的排斥和包含
权限的排斥和包含这块我没有具体看RBAC的规范,一般的作法是经过在资源的操做权限模型中增长自关联模型以定义哪些资源的操做权限是排斥和包含的,在受权时能够看到一样须要维护的只是资源权限的自关联模型。
l 资源权限校验
根据上面的受权模型,在作资源权限校验的时候须要通过如下步骤:
n 判断用户所在的角色是否拥有对资源进行操做的权限
获取用户所拥有的角色,遍历其角色,以各角色创建Session,并经过相似的role.doPrivilege(Resource,Operation)的方式来判断该角色是否具有权限,如具有则直接返回,如不具有则直到遍历结束。
n 递规用户所在角色的父角色判断是否拥有对资源进行操做的权限
当遍历完用户自己的角色获得用户不具有对资源进行该操做的权限时,则开始递规其所在角色的父角色来判断是否拥有对资源进行操做的权限,过程同上,如肯定某角色具有,则返回,如不具有直到递规结束。
l 数据权限校验
在RBAC模型中没有明肯定义数据权限的实现策略,鉴于此首先要讲解下基于RBAC模型的数据受权模型的创建,基于RBAC模型,将数据映射为RBAC中的资源,对数据的操做则映射为资源的操做,一样的是将此资源以及资源的操做构成的权限授予给角色,将用户分配给角色完成数据权限的受权过程。
但根据数据权限校验的需求,数据的权限也是须要继承的,并且数据权限的授予对象须要是多种,这样的话就对上面根据RBAC映射造成的数据权限的受权模型形成了冲击,须要重构上面的受权模型来知足需求。
为实现数据权限的继承,须要将RBAC模型中的资源重构为容许自关联的模型,为实现数据权限可以授予给多种对象,须要将原本资源操做权限授予给角色的模型演变为数据操做权限授予给角色、组织机构或具体人员,根据RBAC模型,一样的创建一个中间对象,此对象和数据操做权限所授予的对象作1对多的关联,在通过这样的重构以后数据权限的受权模型就造成了,也知足了数据权限的继承和授予给多种对象的需求。
图表 2 基于RBAC演变的数据权限模型
上面的图中少画了数据的自关联。
根据上面的数据权限模型,来看看数据权限的校验是怎么样去实现呢?
在作数据权限校验的时候咱们须要实现的为两种方式,一种是获取操做主体具备数据操做权限的所有数据,另一种为分页获取操做主体具备数据操做权限的数据。
就这两种方式分别来进行阐述:
n 获取操做主体具备数据操做权限的所有数据
从数据库中获取全部数据,遍历取出的数据从数据权限模型中获取相应的拥有数据操做权限的权限拥有者,若是该数据未配置数据操做权限的控制,那么就无需对该数据进行权限级的判断,如配置了,则需判断当前用户是否在该数据操做权限所对应的拥有者中,如用户不在,则需递规获取该数据的父数据的操做权限的拥有者,到用户拥有权限或递规结束时终止。
n 分页获取操做主体具备数据操做权限的数据
分页的作法和上面差很少,只是在获取了全部的数据后在内存中作分页返回。
1.2.3. 优缺点分析
从上面的基于RBAC的实现方案中能够看出基于RBAC模型的优势在于:
l 易用和高效的受权方式
用户在进行受权时只需对角色进行受权,以后将相应的角色分配给用户便可。
l 简便和高效的受权模型维护
在技术角度来说,进行受权模型的维护上由于基本只须要维护关联模型而显得简单而高效。
缺点在于:
l 复杂的权限校验
在进行权限校验时须要不断的遍历和递规,形成了性能的影响。
l 对于数据权限的不够支持
没有明确的数据权限模型,能够看到在通过重构的数据权限模型其实已经和RBAC模型有必定的
出入,并且在数据权限的校验上实现起来是很是的低效。
最终根听说明,设计以下系统架构图:
数据项 |
字段名称 |
数据定义 |
必输项 |
检查规则 |
userId |
用户ID |
Varchar(20) |
系统产生(UUID) |
单表惟一 |
userName |
用户名称 |
Varchar(8) |
手工输入 |
不可为空 |
userAccount |
用户账户 |
Varchar(20) |
手工输入 |
全系统惟一 |
userMobile |
移动电话 |
Varchar(11) |
能够为空 |
|
isAdmin |
管理员标志 |
DECIMAL(1,0) |
系统产生 |
一、超级管理员二、企业管理员3用户 |
lockFlag |
账号锁定标志 |
DECIMAL(1,0) |
系统产生 |
是否锁定 一、锁住 0、未锁住 锁定后的用户不能登陆系统 |
departId
|
所属部门ID |
Varchar(20) |
手动选择 |
来源t_sys_org表(orgId) |
departName |
部门名称 |
Varchar(30) |
系统产生 |
|
orgId |
企业ID |
Varchar(20) |
系统产生 |
来源t_sys_org表(orgId) |
orgName |
企业名称 |
Varchar(30) |
系统产生 |
来源t_sys_org表(orgName) |
createBy |
建立人ID |
Varchar(20) |
系统产生 |
|
createName |
建立人名称 |
Varchar(30) |
系统产生 |
|
createTime |
建立时间 |
DATETIME
|
系统产生 |
|
updateBy
|
更新人ID |
Varchar(20) |
系统产生 |
|
updateName |
更新人名称 |
Varchar(30) |
系统产生 |
|
lastUpdateTime |
更新时间 |
DATETIME |
系统产生 |
|
|
|
|
|
|
CREATE TABLE `t_sys_userInfo` (
`userId` VARCHAR(20) NOT NULL COMMENT '用户主键',
`userName` VARCHAR(20) NOT NULL,
`orgId` VARCHAR(20) NOT NULL COMMENT '所属机构ID',
`orgName` VARCHAR(50) NOT NULL COMMENT '所属机构名称',
`orgPath` VARCHAR(120) NOT NULL COMMENT '所属机构路径',
`userAccount` VARCHAR(16) NOT NULL COMMENT '登陆账号',
`userPwd` VARCHAR(16) NOT NULL COMMENT '登陆密码',
`userMobile` VARCHAR(11) NULL DEFAULT NULL COMMENT '移动电话',
`isAdmin` DECIMAL(1,0) NOT NULL DEFAULT '3' COMMENT '一、超级管理员二、企业管理员3用户',
`lockFlag` DECIMAL(1,0) NOT NULL COMMENT '是否锁住 一、锁住 0、未锁住',
`departId` VARCHAR(20) NOT NULL COMMENT '所属部门',
`createBy` VARCHAR(20) NOT NULL,
`createName` VARCHAR(50) NOT NULL COMMENT '建立人',
`createTime` DATETIME NOT NULL COMMENT '建立时间',
`lastUpdateBy` VARCHAR(32) NOT NULL COMMENT '最后修改人ID',
`updateName` VARCHAR(50) NOT NULL COMMENT '最后修改人',
`lastUpdateTime` DATETIME NOT NULL COMMENT '最后修改时间',
PRIMARY KEY (`userId`)
)
COMMENT='用户信息表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
数据项 |
字段名称 |
数据定义 |
必输项 |
检查规则 |
resId |
用户ID |
Varchar(20) |
系统产生(UUID) |
单表惟一 |
resName |
用户名称 |
Varchar(20) |
手工输入 |
不可为空 |
parentId |
用户账户 |
Varchar(20) |
手工输入 |
来源t_sys_resInfo表(resId) |
parentName |
移动电话 |
Varchar(20) |
能够为空 |
来源t_sys_resInfo表(resName) |
resType |
资源类型 |
DECIMAL(1,0) |
手动选择 |
一、目录二、菜单 3.操做权限 检查规则: 一、目录下面,不能添加操做权限 二、菜单下面不能添加目录 三、以此类推
|
resState |
资源状态 |
DECIMAL(1,0) |
手动选择 |
0,不可用 1可用 |
resSort |
资源排序字段 |
DECIMAL(1,0) |
系统产生 |
来源t_sys_org表(orgId) |
resUrl |
资源访问地址 |
Varchar(30) |
手动输入 |
后期自动产生 |
leafCount |
子级菜单数量 |
DECIMAL(1,0) |
系统产生 |
|
resPath |
企业名称 |
Varchar(30) |
系统产生 |
来源t_sys_org表(orgName) |
iconCls |
建立人ID |
Varchar(32) |
系统产生 |
|
CREATE TABLE `t_sys_resInfo` (
`resId` VARCHAR(32) NOT NULL COMMENT '主键ID',
`resName` VARCHAR(128) NOT NULL COMMENT '资源名称',
`parentId` VARCHAR(32) NOT NULL COMMENT '资源父节点',
`parentName` VARCHAR(128) NOT NULL COMMENT '资源父节点名称',
`resType` DECIMAL(1,0) NULL DEFAULT '1' COMMENT '一、功能菜单 2、功能点 3、按钮',
`resState` DECIMAL(1,0) NULL DEFAULT '1' COMMENT '记录资源的状态(可用,不可用):0表示不可用,1表示可用',
`resSort` DECIMAL(8,0) NULL DEFAULT '0' COMMENT '资源排序 ',
`resUrl` VARCHAR(512) NULL DEFAULT '' COMMENT '资源URL地址',
`leafCount` DECIMAL(1,0) NULL DEFAULT '0' COMMENT '子节点数量',
`resPath` VARCHAR(2048) NULL DEFAULT '' COMMENT '记录资源节点的路径:当前菜单的上级菜单,上级菜单的父级菜单',
`iconCls` VARCHAR(20) NULL DEFAULT '' COMMENT '资源图标',
PRIMARY KEY (`resId`)
)
COMMENT='系统资源'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
CREATE TABLE `t_sys_org` (
`orgId` VARCHAR(20) NOT NULL COMMENT '组织主键',
`orgName` VARCHAR(50) NOT NULL COMMENT '组织名称',
`orgShortName` VARCHAR(30) NULL DEFAULT NULL COMMENT '组织简称',
`parentId` VARCHAR(32) NOT NULL COMMENT '组织父节点ID',
`parentName` VARCHAR(50) NOT NULL COMMENT '父节点编码',
`orgType` DECIMAL(1,0) NOT NULL DEFAULT '1' COMMENT '组织的类型 一、企业 二、部门 三、分公司,4,支行',
`orgStatus` DECIMAL(1,0) NOT NULL DEFAULT '1' COMMENT '记录组织的状态是否启用:0,停用/1,启用',
`orgHisStatus` DECIMAL(1,0) NOT NULL DEFAULT '1' COMMENT '0,停用/1,启用',
`orgLinkMan` VARCHAR(50) NULL DEFAULT NULL COMMENT '机构的法人表明名称',
`orgTelephone` VARCHAR(20) NULL DEFAULT NULL COMMENT '机构的联系电话',
`orgFax` VARCHAR(20) NULL DEFAULT NULL COMMENT '机构的传真',
`orgEmail` VARCHAR(100) NULL DEFAULT NULL COMMENT '机构的电子邮箱',
`orgAddress` VARCHAR(200) NULL DEFAULT NULL COMMENT '组织地址',
`orgWebsite` VARCHAR(200) NULL DEFAULT NULL COMMENT '组织的网站',
`leafCount` DECIMAL(1,0) NULL DEFAULT NULL COMMENT '子企业数量',
`orgSort` DECIMAL(10,0) NULL DEFAULT NULL COMMENT '组织排序',
`resIconStyle` VARCHAR(20) NULL DEFAULT '' COMMENT '资源图标',
`orgPath` VARCHAR(2048) NULL DEFAULT NULL COMMENT '记录组织的节点路径',
`createBy` VARCHAR(20) NULL DEFAULT NULL COMMENT '建立人ID',
`createName` VARCHAR(50) NULL DEFAULT NULL COMMENT '建立人',
`createTime` DATETIME NULL DEFAULT NULL COMMENT '建立时间',
`lastUpdateBy` VARCHAR(20) NULL DEFAULT NULL COMMENT '最后修改人ID',
`updateName` VARCHAR(50) NULL DEFAULT NULL COMMENT '最后修改人',
`lastUpdateTime` DATETIME NULL DEFAULT NULL COMMENT '最后修改时间',
PRIMARY KEY (`orgId`)
)
COMMENT='组织架构信息'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
CREATE TABLE `t_sys_role` (
`roleId` VARCHAR(20) NOT NULL COMMENT '角色表主键ID',
`orgId` VARCHAR(20) NULL DEFAULT NULL COMMENT '所属组织',
`orgPath` VARCHAR(20) NULL DEFAULT NULL COMMENT '组织路径',
`orgName` VARCHAR(50) NOT NULL COMMENT '组织名称',
`roleName` VARCHAR(50) NOT NULL COMMENT '角色名称',
`roleDesc` VARCHAR(100) NULL DEFAULT NULL COMMENT '角色描述',
`createBy` VARCHAR(20) NOT NULL COMMENT '建立人ID',
`createName` VARCHAR(50) NOT NULL COMMENT '建立人',
`createTime` DATETIME NOT NULL COMMENT '建立时间',
`lastUpdateBy` VARCHAR(20) NULL DEFAULT NULL COMMENT '最后修改人ID',
`updateName` VARCHAR(50) NULL DEFAULT NULL COMMENT '最后修改人',
`lastUpdateTime` DATETIME NULL DEFAULT NULL COMMENT '最后修改时间',
PRIMARY KEY (`roleId`)
)
COMMENT='角色信息表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
CREATE TABLE `t_sys_userRole` (
`userRoleId` VARCHAR(20) NOT NULL COMMENT '主键ID',
`roleId` VARCHAR(20) NULL DEFAULT NULL COMMENT '角色表主键ID',
`userId` VARCHAR(20) NULL DEFAULT NULL COMMENT '用户主键',
PRIMARY KEY (`userRoleId`)
)
COMMENT='用户角色关系表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
CREATE TABLE `t_sys_roleRes` (
`roleResId` VARCHAR(20) NOT NULL COMMENT '角色资源主键ID',
`roleId` VARCHAR(22) NOT NULL COMMENT '角色表主键ID',
`resId` VARCHAR(20) NOT NULL COMMENT '资源主键',
`isReadWrite` DECIMAL(1,0) NOT NULL DEFAULT 1 COMMENT '1,只读取2,可读写',
PRIMARY KEY (`roleResId`)
)
COMMENT='角色资源关系表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
CREATE TABLE `t_sys_orgRes` (
`orgResId` VARCHAR(20) NOT NULL COMMENT '角色资源主键ID',
`orgId` VARCHAR(22) NOT NULL COMMENT '角色表主键ID',
`resId` VARCHAR(20) NOT NULL COMMENT '资源主键',
`isReadWrite` DECIMAL(1,0) NOT NULL DEFAULT 1 COMMENT '1,只读取2,可读写',
PRIMARY KEY (`orgResId`)
)
COMMENT='角色资源关系表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
相关运营截图: