基于web信息管理系统的权限设计分析和总结
这里讨论的权限只涉及到信息管理系统里面的权限管理,超出此范围的权限管理暂不涉及。
1、权限的应用对象
上面我们已经定义了权限的范围,就是信息系统管理里面的表单操作,那么权限的应用对象就是表单,更进一步说,就是表达表单内容的web管理页面。
2、权限的分类
一个页面的权限范围分为以下几种,也可以叫做基本权限单位。
操作权限:操作权限是一种页面级别的权限,也可以叫做页面权限。包括以下几种
- 新增
- 修改
- 删除
- 查询
在此基础上还可以进行更加详细的一些分类,比如查看他人记录的权限,修改他人记录的权限等。这部分也可以使用下面的记录权限来实现。
按钮权限:针对页面上按钮的权限管理,包括
- u 是否可见
- u 是否可用
有时候,我们可以把按钮权限看作为字段权限。
字段权限:字段在页面的不同状态(新增,修改,查询)下面的各种状态管理。包括
- 是否可见
- 是否可修改
记录权限:记录权限是指用户对某些记录的查看和修改权限。比如客户关系管理系统中,不同界别的系统用户可以看到不同的记录,例如上司可以看他所有下级员工的客户列表等。
3、权限的实现模型
上面的权限分类大概对涉及到页面元素的权限进行了一个比较全面的概括。另外一个问题就是权限管理的实现模型。在大部分的系统中都是用的基于角色控制模型的权限管理。在这样的系统中,创建一系列的角色,然后把基本权限单位分配给这些角色,再把角色分配给用户,这样用户登录系统后,就根据当前用户所拥有的角色可以定位出权限。
在针对信息管理系统中,权限模型有自己的特色,除了角色的概念以外,还有表单权限的概面。第一节里面所讨论的各种权限基本单位不但可以应用到角色上,也可以应用到表单上。
对于应用到表单上的基本权限单位,我们叫做表单的固有权限属性(静态权限)。对于应用到角色上的基本权限单位,我们叫做角色权限属性(动态权限)。用下图来表示:
根据上面的模型,一个用户登录到系统中后,得到某一个表单的权限就和这个表单的固有权限属性和这样用户所拥有的角色有关。
4、权限的计算方式
用户登录后对一个表单进行操作,静态权限只有一个,即表单本身的权限属性,动态权限可以有多个,即用户可以同时属于多个角色,这些角色在这个表单上都有不同的动态权限。用户对这个表单所能进行的操作是由这个动态权限和静态权限的综合作用决定的。进行权限判断分为两个步骤:
1、 动态权限组合:根据用户所属的角色的权限分析得到最终的动态权限集合。
2、 动态权限和静态权限的组合:利用得到的动态权限集合再和静态权限进行综合分析得到用户的最终权限。
在动态权限和动态权限进行组合判断,以及动态权限和静态权限进行组合判断的时候,根据权限类型的不同,使用不同的组合判断方法
对于 操作权限,分为两种组合方法:
或操作:或操作认为,两个层次的权限单位进行比较,只要其中一个权限单位认为“可以做”,那么组合权限结果就是“可以做”。例如对于“增加”这个操作权限,如果角色A设置为可以增加,角色B设置为不可以增加,那么综合的结果就是 可以进行 “增加”
与操作:与操作认为,两个层次的权限单位进行比较,只要其中一个权限单位认为“不可以做”,那么组合权限结果就是“不可以做”。例如: 对于“增加”这个操作权限,如果角色A设置为可以增加,角色B设置为不可以增加,那么综合的结果就是 不可以进行 “增加”
对于字段权限 和 记录权限 只有一种组合方法:
权限并集:也就是说组合的结果是这两种层级的权限单位控制范围的一个相交的结果。例如:对于角色A,他在表单F上的的只读字段为(a,b,c,d),角色B在表单F上的只读字段为(c,d,e,f),那么角色A和角色表的相交结果就是只读字段集合(a,b,c,d,e,f)。
下面两张表显示了不同的权限层次,不同的权限类型在进行权限比较时选择不同的比较方法:
不同的角色之间进行权限比较:
|
角色B-操作权限 |
角色B-字段权限 |
角色B-记录权限 |
角色A-操作权限 |
或操作 |
|
|
角色A-字段权限 |
|
并集 |
|
角色A-记录权限 |
|
|
并集 |
当有多个角色权限是,列入有角色A,B,C,D,先对A,B做计算,然后把计算结果和C进行计算,依次类推。
动态权限和静态权限进行权限比较:
|
动态权限-操作权限 |
动态权限-字段权限 |
动态权限-记录权限 |
静态权限-操作权限 |
与操作 |
|
|
静态权限-字段权限 |
|
并集 |
|
静态权限-记录权限 |
|
|
交集 |
看过基于web信息管理系统的权限设计分析和总结(理论)的一些网友问道,能不能给出这个权限模型的实现,其实模型是一个解决给定问题的理论指导,具体的实现可以有多种方式,可能根据您的项目的实际情况有所不同,这里给出一个是基于sql server数据库的实现。这里提到的只是一些基本的权限信息,您当然可以扩展更多的权限信息。
首先需要定义的是基本权限单位的数据库模型,用下表来表示:(这个表不是独立存在的,而是合并到表单信息表 和 角色权限表中)
权限类型 |
字段名称 |
类型 |
意义 |
操作权限 |
AddAction |
bit |
新增 |
ModifyAction |
bit |
修改 |
|
DeleteAction |
bit |
删除 |
|
SearchAction |
bit |
查询 |
|
字段权限 (字段之间以逗号 , 分割) |
ReadOnlyColumnsOnAdd |
Nvarchar(1000) |
只读字段(新增) |
HiddenColumnsOnAdd |
Nvarchar(1000) |
隐藏字段(新增) |
|
ReadOnlyColumnsOnModify |
Nvarchar(1000) |
只读字段(修改) |
|
HiddenColumnsOnModify |
Nvarchar(1000) |
隐藏字段(修改) |
|
HiddenColumnsOnSearch |
Nvarchar(1000) |
隐藏字段(查询) |
|
纪录权限 (一段表示权限范围的语句,在本实现中,就是一个sql语句的片断)
|
ReadOnlyRecords |
Nvarchar(1000) |
只读纪录 |
HiddenRecords |
Nvarchar(1000) |
隐藏纪录 |
接下来是表单信息表,表单信息表有一些基本的表单信息,例如表单名称等,同时表单信息表也拥有以上的基本权限数据,这些权限信息构成了表单的固有权限属性(静态权限),一个简单的表单信息表如下所示:
表单信息表:Forms
字段名称 |
类型 |
意义 |
|
FormID |
Nvarchar(100) |
表单ID |
|
FormName |
Nvarchar(100) |
表单名称 |
|
AddAction |
bit |
新增 |
表单的固有权限属性 (静态权限) |
ModifyAction |
bit |
修改 |
|
DeleteAction |
bit |
删除 |
|
SearchAction |
bit |
查询 |
|
ReadOnlyColumnsOnAdd |
Nvarchar(1000) |
只读字段(新增) |
|
HiddenColumnsOnAdd |
Nvarchar(1000) |
隐藏字段(新增) |
|
ReadOnlyColumnsOnModify |
Nvarchar(1000) |
只读字段(修改) |
|
HiddenColumnsOnModify |
Nvarchar(1000) |
隐藏字段(修改) |
|
HiddenColumnsOnSearch |
Nvarchar(1000) |
隐藏字段(查询) |
|
ReadOnlyRecords |
Nvarchar(1000) |
只读纪录 |
|
HiddenRecords |
Nvarchar(1000) |
隐藏纪录 |
下面就是角色表了,角色表相当简单,只包含一个角色名称就可以了:
角色表:Roles
字段名称 |
类型 |
意义 |
RoleID |
Nvarchar(100) |
角色ID |
RoleName |
Nvarchar(100) |
角色名称 |
定义好了角色表,接下来就是角色权限了,就是角色在每个表单上的权限表现形式,当前这个表就需要跟角色以及表单有关了,具体的结果如下:
角色权限表: RolePurview
字段名称 |
类型 |
意义 |
|
RolePurviewID |
Nvarchar(100) |
主键 |
|
FormID |
Nvarchar(100) |
表单ID 外键,关联到表单信息表的FormID |
|
RoleID |
Nvarchar(100) |
角色ID 外键,关联到角色表的RoleID |
|
AddAction |
bit |
新增 |
表单的角色权限属性 (动态权限) |
ModifyAction |
bit |
修改 |
|
DeleteAction |
bit |
删除 |
|
SearchAction |
bit |
查询 |
|
ReadOnlyColumnsOnAdd |
Nvarchar(1000) |
只读字段(新增) |
|
HiddenColumnsOnAdd |
Nvarchar(1000) |
隐藏字段(新增) |
|
ReadOnlyColumnsOnModify |
Nvarchar(1000) |
只读字段(修改) |
|
HiddenColumnsOnModify |
Nvarchar(1000) |
隐藏字段(修改) |
|
HiddenColumnsOnSearch |
Nvarchar(1000) |
隐藏字段(查询) |
|
ReadOnlyRecords |
Nvarchar(1000) |
只读纪录 |
|
HiddenRecords |
Nvarchar(1000) |
隐藏纪录 |
当然要完成整个模型,还需要用户信息表以及用户角色表
用户信息表:Users
字段名称 |
类型 |
意义 |
UserID |
Nvarchar(100) |
用户ID |
UserName |
Nvarchar(100) |
用户名称 |
用户角色表:UserInRoles
字段名称 |
类型 |
意义 |
UserInRoleID |
Nvarchar(100) |
主键 |
UserID |
Nvarchar(100) |
用户ID 外键,关联到用户表的UserID |
RoleID |
Nvarchar(100) |
角色ID 外键,关联到角色表的RoleID |
到目前为止,我们完成这个模型所需要的表都出场了,下面的图表示了他们之间的关系:
在下节中将实现具体的权限的计算公式。XZZ
首先需要一个存储过程来实现计算用户在表单上的权限,这个存储过程接受两个参数,用户ID和表单ID,在这个存储过程里面使用一条sql语句来计算用户在表单上的权限,如下所示:
Code
-- =============================================
--计算用户对表单的权限
-- =============================================
create PROCEDURE [dbo].[sp_GetUserPurveiewOnMenu]
@userID nvarchar(100) ,--用户ID
@formID nvarchar(100) --表单ID
AS
BEGIN
SELECT rp.formID,
u.userID,
--计算记录权限:只读记录
dbo.fun_Purview_GetRecordPurview(u.userID,rp.formID,'ReadOnlyRecords') as ReadOnlyRecords,
--计算记录权限:隐藏记录记录
dbo.fun_Purview_GetRecordPurview(u.userID,rp.formID,'HiddenRecord') as HiddenRecord,
--计算字段权限:只读记录(新增)
dbo.fun_Purview_GetColumns(u.userID,rp.formID,'ReadOnlyColumnsOnAdd') as ReadOnlyColumnsOnAdd,
--计算字段权限:隐藏记录(新增)
dbo.fun_Purview_GetColumns(u.userID,rp.formID,'HiddenColumnsOnAdd') as HiddenColumnsOnAdd,
--计算字段权限:只读记录(修改)
dbo.fun_Purview_GetColumns(u.userID,rp.formID,'ReadOnlyColumnsOnModify') as ReadOnlyColumnsOnModify,
--计算字段权限:隐藏记录(修改)
dbo.fun_Purview_GetColumns(u.userID,rp.formID,'HiddenColumnsOnModify') as HiddenColumnsOnModify,
--计算字段权限:隐藏记录(查询)
dbo.fun_Purview_GetColumns(u.userID,rp.formID,'HiddenColumnsOnSearch') as HiddenColumnsOnSearch,
--计算操作权限:新增
(CASE
WHEN (SUM((CAST((CASE f.AddAction WHEN 0 THEN 0
ELSE rp.AddAction
END) AS int)))) > 0
THEN cast(1 as bit)
ELSE cast(0 as bit)
END) as AddAction,
--计算操作权限:修改
(CASE
WHEN ( SUM((CAST((CASE f.ModifyAction WHEN 0 THEN 0
ELSE rp.ModifyAction
END) AS int))) ) > 0
THEN cast(1 as bit)
ELSE cast(0 as bit)
END) as ModifyAction,
--计算操作权限:删除
(CASE
WHEN ( SUM((CAST((CASE f.DeleteAction WHEN 0 THEN 0
ELSE rp.DeleteAction
END) AS int)))) > 0
THEN cast(1 as bit)
ELSE cast(0 as bit)
END) as DeleteAction,
--计算操作权限:查询
(CASE
WHEN ( SUM((CAST((CASE f.SearchAction WHEN 0 THEN 0
ELSE rp.SearchAction
END) AS int)))) > 0
THEN cast(1 as bit)
ELSE cast(0 as bit)
END) as SearchAction
FROM users u,
userinroles ur,
RolePurview rp,
forms f
WHERE u.userID = ur.userID
AND ur.roleID = rp.roleID
AND rp.formID = f.formID
AND u.userID = @userid
AND f.formID = @formID
GROUP BY rp.formID,u.userID
END
在这个存储过程里面,有两个用户函数,分别用于计算字段权限和记录权限。
用于计算字段权限的函数是fun_Purview_GetColumns,这个函数接受三个参数,分别是用户ID、表单ID和字段权限类型,具体如下所示:
Code
-- =============================================
-- 计算字段权限
-- =============================================
create FUNCTION [dbo].[fun_Purview_GetColumns]
(
@userID nvarchar(100),--用户ID
@formID nvarchar(100),--表单ID
@columnType varchar(50)--字段权限类型
)
RETURNS nvarchar(2000)
AS
BEGIN
declare @columsID nvarchar(4000),@tem nvarchar(1000),@c cursor
set @columsID=''
set @tem = ''
if @columnType = 'ReadOnlyColumnsOnAdd' -- 计算只读字段集合(新增)。对于其他字段集合类似
begin
set @c = cursor for select ReadOnlyColumnsOnAdd from forms where formID=@formID
union
select ReadOnlyColumnsOnAdd from RolePurview where roleID in(
select roleID from UserInRoles where userID=@userid
)
open @c
fetch next from @c into @tem
while @@fetch_status =0
begin
if @tem is not null
begin
set @columsID = @columsID +','+ @tem
end
fetch next from @c into @tem
end
close @c
deallocate @c
end
return @columsID
END
用于计算记录权限的函数是fun_Purview_GetRecordPurview,这个函数接受三个参数,分别是用户ID、表单ID和记录权限类型,具体如下所示:
Code
-- =============================================
--计算记录权限
-- =============================================
alter FUNCTION [dbo].[fun_Purview_GetRecordPurview]
(
@userid int,--用户ID
@formID int ,--表单ID
@recordPurviewType varchar(100)--记录权限类型
)
RETURNS nvarchar(4000)
AS
BEGIN
declare @recordPurviewSql nvarchar(4000),@c2 cursor,@sql nvarchar(4000),
@formRecordPurviewExpression nvarchar(4000)
set @recordPurviewSql = ''
set @sql = ''
if @recordPurviewType ='ReadOnlyRecords'--计算只读记录,对于隐藏记录类似
begin
set @c2 = cursor for select ReadOnlyRecords from RolePurivew where roleID in( select roleID from UserInRoles where userID=@userid
) and formID=@formID
open @c2
fetch next from @c2 into @sql
while @@fetch_status =0
begin
if @sql is not null and @sql<> ''
begin
--对于角色之间的记录权限,使用并集
set @recordPurviewSql = @recordPurviewSql +'('+@sql+')' + ' or '
end
fetch next from @c2 into @sql
end
close @c2
deallocate @c2
if len(@recordPurviewSql) > 3
begin
set @recordPurviewSql = substring(@recordPurviewSql,1,len(@recordPurviewSql)-3)
end
select @formRecordPurviewExpression= ReadOnlyRecords from forms where formID=@formID
if @recordPurviewSql is not null and @recordPurviewSql <>''
begin
set @recordPurviewSql = '('+@recordPurviewSql+')'
if @formRecordPurviewExpression is not null and @formRecordPurviewExpression <>''
--对于角色和表单的记录权限,使用交集
set @recordPurviewSql = @recordPurviewSql +' and ('+@formRecordPurviewExpression+')'
end
else
begin
if @formRecordPurviewExpression is not null and @formRecordPurviewExpression <>''
set @recordPurviewSql = '('+@formRecordPurviewExpression+')'
end
end
return @recordPurviewSql
END
使用上面的函数就可以计算用户在表单上的权限了。
另外,您也可以对此权限模型进行扩展,比如您可以对角色设置一个角色的权限计算类型属性.
如果此角色是悲观型的,那么此角色和其他角色进行权限计算是,使用最小的权限集合。具体来说对于字段权限,使用与操作,对于字段权限和记录权限,使用交集。如果此角色是乐观型的,那么此角色和其他角色进行权限计算是,使用最大的权限集合。具体来说对于字段权限,使用或操作,对于字段权限和记录权限,使用并集。
在具体的项目实践中,为了提高性能,可以设置一些缓存,例如可以把上面的计算结果缓存到一个数据表里面,作为一级数据缓存。在程序中,还可以使用二级缓存在内存中保存用户的权限,当然这样做在提高性能的同时,也增加了程序的复杂度和数据的冗余,需要处理更多的地方。