浅谈数据权限的实现方法和作用机制
2014-03-07 13:03
99 查看
在企业开发中,往往对权限的控制有较高的要求,其中也经常会被要求实现对业务数据操作进行权限控制。在这里,分享一下本人在企业开发中的数据权限的实现经验。本文所用的方法和实例,可在CSDN的代码托管平台找到。需要的童鞋可点击:https://code.csdn.net/xuanbg/starx-bip自行查看或下载。
要想管理数据权限,首先得定义数据的归属和用户对数据的访问范围,和功能权限相比,这一点是数据权限特有的。那么数据的归属要怎么定义呢?一般来说,可在数据的生产者和数据的生产部门这两个维度进行定义。例如:
序号 收款金额 收款部门 收款人
1 3000.00 A部门 张三
2 2000.00 B部门 李四
3 50000.00 A部门 王五
从上表可以看出来,第一行数据中的3000元是A部门的张三收取的,而第二行数据中的2000元则是B部门的李四收取。如果授权给张三只能看到他自己的业务数据,那么对于张三来说,第二行和第三行数据就不应该看到。如果授权王五能够看到A部门的业务数据,则王五能看到的数据是第一行和第三行。如果授权李四能够管理整个公司的收款业务数据,那么李四应该可以读取上表里的所有数据。
这里就又涉及到了部门、机构这些概念,这里且不深谈。一般来说,业务数据的权限类型是只读和读写两种,数据的访问范围则稍复杂,有如下这么几种:
1、仅本人,意味着用户只能访问其本人产生的业务数据2、仅本部门,意味着用户可以访问其所在部门所有用户产生的业务数据3、本部门全部,意味着用户不但可以访问其所在部门所有用户产生的业务数据,还可以访问其所在部门下属部门所有用户产生的业务数据4、本机构全部,意味着用户可以访问其所在机构(通常是整个分子公司)所有的业务数据5、整个公司,意味着用户可以获取包括母公司及母公司其它分子公司的全部数据6、自定义,用户可以以不同的访问权限访问指定部门的业务数据,譬如A部门只读,B部门可读写。涉及权限,无非是:角色、角色成员和角色权限。功能权限如此,数据权限也没有区别。在数据模型的设计上,就会有如下结构:
角色表:Id,角色名称,以及其它字段
角色成员表:Id,角色Id,成员Id
角色数据权限表:Id,角色Id,数据表名或Id,访问范围,访问权限
以上三张表结合起来,我们就可以知道当前登录用户能访问哪些数据表以及只读还是读写权限了。但是仅仅知道这些还是不够的,我们需要一种高效的方法来对数据进行筛选,以便用户能够获取且仅获取他能够获取的数据。然后在每条数据上附加上权限标签来告诉系统这条数据用户是只读还是读写。
在获取数据前,我们首先需要知道特定的数据表(这个由业务模块决定,不同的业务必然使用不同的数据表),当前用户被授权访问什么范围的数据。由于用户可能是多个角色的成员,所以这个需要通过一个表值函数来合并所有角色权限,从而获取当前用户的真正权限。函数源代码如下:
知道用户被授权的访问范围之后,1和2两种情况简单加个条件过滤就行了,3-6四种情况需要用到表值函数来获取具体的授权访问范围和访问权限。
在函数里还调用了另一个函数来获取机构或根机构的Id,并以此为依据获取该节点的编码,只要把组织机构的编码设计值为类似01、0101这样的层级编码,就很容易使用一个like来得到所有下属节点的Id。最后,利用inner join 合并两表内容并取交集的特性,把业务数据表和表值函数按组织机构Id 来一次inner join,就能把非授权范围内的数据全部过滤掉,并且把所有业务数据加上访问权限的类型码。
要想管理数据权限,首先得定义数据的归属和用户对数据的访问范围,和功能权限相比,这一点是数据权限特有的。那么数据的归属要怎么定义呢?一般来说,可在数据的生产者和数据的生产部门这两个维度进行定义。例如:
序号 收款金额 收款部门 收款人
1 3000.00 A部门 张三
2 2000.00 B部门 李四
3 50000.00 A部门 王五
从上表可以看出来,第一行数据中的3000元是A部门的张三收取的,而第二行数据中的2000元则是B部门的李四收取。如果授权给张三只能看到他自己的业务数据,那么对于张三来说,第二行和第三行数据就不应该看到。如果授权王五能够看到A部门的业务数据,则王五能看到的数据是第一行和第三行。如果授权李四能够管理整个公司的收款业务数据,那么李四应该可以读取上表里的所有数据。
这里就又涉及到了部门、机构这些概念,这里且不深谈。一般来说,业务数据的权限类型是只读和读写两种,数据的访问范围则稍复杂,有如下这么几种:
1、仅本人,意味着用户只能访问其本人产生的业务数据2、仅本部门,意味着用户可以访问其所在部门所有用户产生的业务数据3、本部门全部,意味着用户不但可以访问其所在部门所有用户产生的业务数据,还可以访问其所在部门下属部门所有用户产生的业务数据4、本机构全部,意味着用户可以访问其所在机构(通常是整个分子公司)所有的业务数据5、整个公司,意味着用户可以获取包括母公司及母公司其它分子公司的全部数据6、自定义,用户可以以不同的访问权限访问指定部门的业务数据,譬如A部门只读,B部门可读写。涉及权限,无非是:角色、角色成员和角色权限。功能权限如此,数据权限也没有区别。在数据模型的设计上,就会有如下结构:
角色表:Id,角色名称,以及其它字段
角色成员表:Id,角色Id,成员Id
角色数据权限表:Id,角色Id,数据表名或Id,访问范围,访问权限
以上三张表结合起来,我们就可以知道当前登录用户能访问哪些数据表以及只读还是读写权限了。但是仅仅知道这些还是不够的,我们需要一种高效的方法来对数据进行筛选,以便用户能够获取且仅获取他能够获取的数据。然后在每条数据上附加上权限标签来告诉系统这条数据用户是只读还是读写。
在获取数据前,我们首先需要知道特定的数据表(这个由业务模块决定,不同的业务必然使用不同的数据表),当前用户被授权访问什么范围的数据。由于用户可能是多个角色的成员,所以这个需要通过一个表值函数来合并所有角色权限,从而获取当前用户的真正权限。函数源代码如下:
/*****表值函数:获取当前登录用户有效数据访问范围类型和权限*****/ IF EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'User_DataPerm') AND OBJECTPROPERTY(id, N'ISTABLEFUNCTION') = 1) DROP FUNCTION User_DataPerm GO CREATE FUNCTION User_DataPerm( @ModuleId VARCHAR(36), --模块Id @UserId VARCHAR(36), --当前登录用户Id @OrgId VARCHAR(36) --当前登录部门Id ) RETURNS TABLE AS RETURN select D.TableId, max(D.Permission) as Permission, D.Mode from( select R.RoleId from Sys_Role_User R where R.UserId = @UserId union select R.RoleId from Sys_Role_UserGroup R join Sys_UserGroupItem G on G.GroupId = R.GroupId and G.UserId = @UserId union select R.RoleId from Sys_Role_Position R join Sys_User_Org P on P.OrgId = R.OrgId and P.UserId = @UserId join Sys_Organization O on O.Id = R.OrgId and O.ParentId = @OrgId ) R join Sys_RolePerm_Data D on D.RoleId = R.RoleId join Sys_ModuleTable M on M.Id = D.TableId and M.ModuleId = @ModuleId group by D.TableId, D.Mode having max(D.Permission) > 0 GO
知道用户被授权的访问范围之后,1和2两种情况简单加个条件过滤就行了,3-6四种情况需要用到表值函数来获取具体的授权访问范围和访问权限。
/*****表值函数:获取当前登录用户数据访问范围和权限*****/ IF EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'User_Data') AND OBJECTPROPERTY(id, N'ISTABLEFUNCTION') = 1) DROP FUNCTION User_Data GO CREATE FUNCTION User_Data( @ModuleId VARCHAR(36), --模块Id @UserId VARCHAR(36), --当前登录用户Id @OrgId VARCHAR(36) --当前登录部门Id ) RETURNS @PermScope TABLE( OrgId VARCHAR(36), Permission INT ) AS BEGIN DECLARE @Table VARCHAR(36) DECLARE @Code VARCHAR(36) DECLARE @Mode INT DECLARE @Permission INT select @Table = TableId, @Mode = Mode, @Permission = Permission from dbo.User_DataPerm(@ModuleId, @UserId, @OrgId) if @Mode = 4 insert into @PermScope select RDI.OrgId, RDI.Permission from Sys_RolePerm_DataItem RDI join Sys_RolePerm_Data RD on RD.Id = RDI.PermDateId and RD.TableId = @Table else begin if @Mode = 3 select @OrgId = dbo.GetOrgId(@OrgId, 0) if @Mode = 2 select @OrgId = dbo.GetOrgId(@OrgId, 1) select @Code = Code from Sys_Organization where Id = @OrgId insert into @PermScope select Id, @Permission from Sys_Organization where Code like @Code + '%' end RETURN END GO
/*****标量值函数:获取上级或根机构Id*****/ IF EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'GetOrgId') AND OBJECTPROPERTY(id, N'ISSCALARFUNCTION') = 1) DROP FUNCTION GetOrgId GO CREATE FUNCTION GetOrgId ( @DeptId VARCHAR(36), --部门Id @Type INT --机构类型:0、根机构;1、上级机构 ) RETURNS NVARCHAR(36) AS BEGIN DECLARE @NodeType INT = 0 DECLARE @ParentId VARCHAR(36) while @NodeType != 1 begin select @NodeType = NodeType * @Type, @ParentId = ParentId from Sys_Organization where Id = @DeptId if @ParentId is null set @NodeType = 1 if @NodeType != 1 set @DeptId = @ParentId end RETURN(@DeptId) END GO
在函数里还调用了另一个函数来获取机构或根机构的Id,并以此为依据获取该节点的编码,只要把组织机构的编码设计值为类似01、0101这样的层级编码,就很容易使用一个like来得到所有下属节点的Id。最后,利用inner join 合并两表内容并取交集的特性,把业务数据表和表值函数按组织机构Id 来一次inner join,就能把非授权范围内的数据全部过滤掉,并且把所有业务数据加上访问权限的类型码。
相关文章推荐
- 实现数据权限控制的一种方法
- 简易插件机制的实现方法浅谈
- 实现数据权限控制的一种方法
- 实现数据权限控制的一种方法
- 使用navicat 8实现创建数据库和导入数据 管理用户与权限[图文方法]
- MSBI实现用户的数据权限控制方法
- 使用navicat 8实现创建数据库和导入数据 管理用户与权限[图文方法]
- 在ASP.NET 2.0中数据绑定的实现方法
- C#.NET 大型通用信息化系统集成快速开发平台 4.0 版本 - 省市区数据权限的实现效果
- 从MySQL导入导出大量数据的程序实现方法
- spring security动态配置url权限的2种实现方法
- 利用反射机制,获取类的字段、方法、并实现简单调用
- C#实现动态数据绘图graphic的方法示例
- 浅谈数据仓库建设中的数据建模方法
- Bootstrap Table实现定时刷新数据的方法
- 利用Python代码实现数据可视化的5种方法详解
- ajax中用josnp接收josn数据的实现方法
- Filter包装response,重写response的getWriter方法实现网络数据压缩
- python操作mongodb根据_id查询数据的实现方法
- Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构