『数据库权限设计』在Sqlserver关系数据库实现行列级别的权限设计

2024-06-17 17:57:42 浏览数 (1)

在BI的分析模型里,很常用的权限设置是行级别的权限控制,不同人可以查看不同的维度成员数据,如销售经理可以看到所有区域的数据,各业务人员,只能看到自己范围内的数据。

当然还有列权限的控制,如控制特定用户如财务用户可以访问某个字段如成本及其相关的衍生度量值,其他用户不可访问。

这些在PowerBI建模里,都不是难事。

但问题来了,不是所有的数据,都通过建模后分发的,关系型数据库能否也实现类似效果呢?

经过一番研究,在Sqlserver上是可以实现的,其他数据库暂时没精力研究,在Sqlserver2016及以后,可以实现这种行级别的权限控制。具体的实现代码如下:

代码语言:javascript复制
-- 创建数据库和架构
CREATE DATABASE SalesDB;
GO

USE SalesDB;
GO

CREATE SCHEMA Security;
GO


-- 创建用户
CREATE USER Manager WITHOUT LOGIN;
CREATE USER Employee1 WITHOUT LOGIN;
CREATE USER Employee2 WITHOUT LOGIN;
CREATE USER Employee3 WITHOUT LOGIN;
GO


-- 创建目标表
CREATE TABLE dbo.Orders (
    OrderID INT PRIMARY KEY,
    SalesRep NVARCHAR(50),
    OrderAmount DECIMAL(18, 2)
);
GO

-- 插入示例数据
INSERT INTO dbo.Orders (OrderID, SalesRep, OrderAmount)
VALUES 
    (1, '1', 100.00),
    (2, '2', 200.00),
    (3, '3', 300.00),
    (4, '4', 400.00);
GO



-- 创建匹配表
CREATE TABLE Security.UserAccess (
    UserID NVARCHAR(50),
    CanViewUserID NVARCHAR(50)
);
GO

-- 插入示例数据
INSERT INTO Security.UserAccess (UserID, CanViewUserID)
VALUES 
    ('Manager', '1'),
    ('Manager', '2'),
    ('Manager', '3'),
    ('Employee1', '1'),
    ('Employee2', '2'),
    ('Employee3', '3');
GO


-- 创建行级别安全策略函数
CREATE FUNCTION Security.fn_securitypredicate(@SalesRep AS NVARCHAR(50))
RETURNS TABLE
WITH SCHEMABINDING
AS
    RETURN SELECT 1 AS fn_securitypredicate_result
    FROM Security.UserAccess
    WHERE CanViewUserID = @SalesRep
          AND UserID = USER_NAME();
GO



-- 删除已存在的安全策略
DROP SECURITY POLICY IF EXISTS SalesFilter;
GO

-- 创建新的安全策略并应用于目标表
CREATE SECURITY POLICY SalesFilter
ADD FILTER PREDICATE Security.fn_securitypredicate(SalesRep)
ON dbo.Orders
WITH (STATE = ON);
GO


-- 授予用户对 Orders 表的 SELECT 权限
GRANT SELECT ON dbo.Orders TO Manager;
GRANT SELECT ON dbo.Orders TO Employee1;
GRANT SELECT ON dbo.Orders TO Employee2;
GRANT SELECT ON dbo.Orders TO Employee3;
GO


-- 测试 Manager 用户
EXECUTE AS USER = 'Manager';
SELECT * FROM dbo.Orders;
REVERT;
GO


-- 测试 Employee1 用户
EXECUTE AS USER = 'Employee1';
SELECT * FROM dbo.Orders;
REVERT;
GO

-- 测试 Employee1 用户
EXECUTE AS USER = 'Employee2';
SELECT * FROM dbo.Orders;
REVERT;
GO

-- 测试 Employee1 用户
EXECUTE AS USER = 'Employee3';
SELECT * FROM dbo.Orders;
REVERT;
GO

上面的代码,使用EXECUTE AS USER模拟不同用户访问的效果。但如果用户层也使用这样一段代码,去模拟其他用户,岂不是白干了?

当然一般的用户,没有办法执行EXECUTE AS USER这个语句的,实在不放心,可以运行以下的代码排查下哪些用户有这个权限(sa这种管理员权限肯定有,在以下语句里返回空是正常的)。

代码语言:javascript复制
SELECT pr.name AS principal_name, pr.type_desc AS principal_type, 
       pe.permission_name, pe.state_desc AS permission_state
FROM sys.database_permissions AS pe
JOIN sys.database_principals AS pr
    ON pe.grantee_principal_id = pr.principal_id
WHERE pe.permission_name = 'IMPERSONATE';

上面的是行级别的权限,列级别的权限,就没那么通用,就需要自己写个视图封装下,例如下面的代码,做一个匹配表,然后有权限的正常显示,没权限的返回NULL。

总结

有了在关系数据库里控制权限,可以更方便地分发数据,不局限于olap模型,特别是对于没条件使用olap建模技术,或者一些明细数据没必要建模后分享,用户需要享有更大的自主性时,这是一个不错的数据分享方案。

最后,有企业项目需求,随时找我

非常难得的全栈开发能力,从数据采集、生产、ETL处理清洗、建模、报表自动化等都能胜任,可以低成本、快速交付高质量项目。

专业人做专业事,没有一个工具简单到可以瞬间让普通人上手并产生巨大生产力。就如简单如Excel的OFFICE工具不同人使用都有很大的差距,更不用说RPA需要有编程思维群体才能深入掌握。

笔者15年数据及编程能力,尚且需要全时间学习一个月才稍微有感觉可以随心所欲根据需求做一些应用出来(效率还带不断练习提升)。目前已经是资深的RPA领域专家,能解决各种企业现实环境难题。

笔者能够带给你:花小成本,可以带来企业数据化流程自动化,带给企业立竿见影的降本增效。

借助笔者独特的多工具的熟练使用优势。借助低代码平台与工具,培训企业员工掌握并持续赋能业务,让业务部门减少IT团队依赖度,一样可以在办公自动化领域大有作为。

0 人点赞