SQL Server使用视图做权限控制
問題引入
這天老鳥火急火燎的跑到菜鳥旁邊,想必是遇到什么難題了:“現在有這么一個場景,假如有三種角色,并且存在層級關系,他們需要訪問同一個數據源表,但是需要做權限控制,使得每種角色只能看到自己及以下層級的數據。比如:公司有CEO,Manger和普通的employee三種角色,CEO可以查看CEO、Manager和employee層級的數據;Manger只能查看Manger和employee的數據,不能查看CEO層級;而employee只能查看employee的數據,不能查看CEO和Manager級別的數據。這個在SQL Server有比較簡單清爽的實現方法嗎?”。老鳥這個問題的確問得非常有水準,這個場景也非常普遍,菜鳥頓時陷入了無邊的困境。
問題分析
在關系型數據庫SQL Server中,權限的確不能達到行列級別這么細粒度的控制,這也是菜鳥為什么陷入困境的原因。但是,突然菜鳥靈魂出竅,靈光一現,像是被雷劈中一般的感覺:雖然SQL Server基于表無法達到那么細粒度的權限控制,但是我們可以建立視圖(VIEW),用視圖來建立正式表的行、列過濾,然后在視圖對象上做權限控制,最終達到對三個層級的權限控制的目的,想到這里菜鳥立馬赫然開朗。
解決問題
菜鳥越想越激動,說打就打,說干就干,于是開始了萬里長征。
測試環境準備
創建測試數據庫Test,接著創建三個用戶CEO,Manager和employee,然后創建測試表tb_Test_ViewPermission,最后插入三條測試數據,每個層級一條數據。
IF DB_ID('Test') IS NULLCREATE DATABASE Test; GOUSE Test GO--create three logins(CEO, manager, employee) --create login CEO IF EXISTS(SELECT *FROM sys.sysloginsWHERE name = 'CEO') BEGINDROP LOGIN CEO; END GO CREATE LOGIN CEO with password='CEODbo',check_policy = off; GO--create user CEO IF USER_ID('CEO') is not nullDROP USER CEO; GO CREATE USER CEO FOR LOGIN CEO; GO--create login Manager IF EXISTS(SELECT *FROM sys.sysloginsWHERE name = 'Manager') BEGINDROP LOGIN Manager; END GO CREATE LOGIN Manager with password='ManagerDbo',check_policy = off; GO--create user manager IF USER_ID('Manager') is not nullDROP USER Manager; GO CREATE USER Manager FOR LOGIN Manager; GO--create login employee IF EXISTS(SELECT *FROM sys.sysloginsWHERE name = 'employee') BEGINDROP LOGIN employee; END GO CREATE LOGIN employee with password='employeeDbo',check_policy = off; GO--create user employee IF USER_ID('employee') is not nullDROP USER employee GO CREATE USER employee FOR LOGIN employee; GO--create basic TABLE IF OBJECT_ID('dbo.tb_Test_ViewPermission','u')is not nullDROP TABLE dbo.tb_Test_ViewPermission ; GO CREATE TABLE dbo.tb_Test_ViewPermission (id int identity(1,1) not null primary key,name varchar(20) not null,level_no int not null,title varchar(20) null,viewByCEO char(1) not null,viewByManager char(1) not null,viewByEmployee char(1) not null,salary decimal(9,2) not null );--data init. INSERT INTO dbo.tb_Test_ViewPermission SELECT 'AA',0,'CEO','Y','Y','Y',1000000.0 union all SELECT 'BB',1,'Manager','Y','Y','Y',100000.0 union all SELECT 'CC',2,'employee','Y','Y','Y',10000.0 ; GO創建三個視圖
表對象和數據準備完畢后,接著我們建立三個視圖,分別過濾出自己所在層級及以下層級的數據。比如,CEO包含CEO、Manager和employee層級數據;Manger包含Manger和employee層級數據;employee僅包含employee層級數據。
USE Test GO --create views for CEO querying, CEO can get all the data IF OBJECT_ID('dbo.v_employeeinfo_forCEO','v')is not nullDROP VIEW dbo.v_employeeinfo_forCEO ; GO CREATE VIEW dbo.v_employeeinfo_forCEO AS SELECT * FROM dbo.tb_Test_ViewPermission WITH(NOLOCK) WHERE level_no >= 0; GO--create views for Manager querying, Manger can get manger group & employee group data IF OBJECT_ID('dbo.v_employeeinfo_forManager','v')is not nullDROP VIEW dbo.v_employeeinfo_forManager ; Go CREATE VIEW dbo.v_employeeinfo_forManager AS SELECT name,level_no,title,viewByManager,viewByEmployee,salary FROM dbo.tb_Test_ViewPermission WITH(NOLOCK) WHERE level_no >= 1; GO--create views for Employee querying, employee just can get employee group data IF OBJECT_ID('dbo.v_employeeinfo_forEmployee','v')is not nullDROP VIEW dbo.v_employeeinfo_forEmployee ; GO CREATE VIEW dbo.v_employeeinfo_forEmployee AS SELECT name,level_no,title,viewByEmployee,salary FROM dbo.tb_Test_ViewPermission WITH(NOLOCK) WHERE level_no >= 2; GO權限設置
所有視圖創建完畢后,接下來是最為關鍵的步驟,就是對視圖權限的設置。基本的思路是:拿掉所有用戶對于基表的權限,對于視圖需要拿掉自己以下層級用戶權限,然后給予視圖自己層級用戶的查看權限。比如:Manager層級視圖dbo.v_employeeinfo_forManager需要拿掉employee的權限,授予Manager查詢權限。
USE Test GO --====permission init. --deny all permission to user for TABLE DENY ALL ON dbo.tb_Test_ViewPermission TO CEO; DENY ALL ON dbo.tb_Test_ViewPermission TO Manager; DENY ALL ON dbo.tb_Test_ViewPermission TO employee;--deny permission for Manager & employee DENY ALL ON dbo.v_employeeinfo_forCEO TO Manager; DENY ALL ON dbo.v_employeeinfo_forCEO TO employee;DENY ALL ON dbo.v_employeeinfo_forManager TO employee;--Grant query permission for CEO & Manager & Employee GRANT SELECT ON dbo.v_employeeinfo_forCEO TO CEO;GRANT SELECT ON dbo.v_employeeinfo_forManager TO Manager;GRANT SELECT ON dbo.v_employeeinfo_forEmployee TO employee; GO權限測試
以上所有工作準備完畢后,接下來就是最緊張的權限驗證環節了,時間才是檢驗真理的唯一標準。
CEO權限測試
按照預期,CEO應該不能訪問基表數據,會報告異常,但是可以查詢CEO,manager和employee層級數據,總共三條。測試語句如下,將SSMS的結果顯示切換為text模式,或者直接快捷鍵ctrl + t。
--CEO query test USE test GO--CEO cann't read data from basic table SELECT * FROM dbo.tb_Test_ViewPermission WITH(NOLOCK)--CEO all read the data from CEO group SELECT CAST(CURRENT_USER AS VARCHAR(10)) AS 'Who am i',* FROM v_employeeinfo_forCEO WITH(NOLOCK) GO結果顯示如下,測試結果的確與預期吻合。
Manager權限測試
預期是Manger對基表沒有訪問權限,也沒有CEO視圖的訪問權限,但是可以查看到Manger和普通employee的數據,也就是會返回兩條數據。
--Manager query test use test GO--Manager cann't read data from basic table SELECT * FROM dbo.tb_Test_ViewPermission WITH(NOLOCK)--Manager can't read the data from CEO group SELECT * FROM v_employeeinfo_forCEO WITH(NOLOCK) GO--manager can read data from manager group SELECT CAST(CURRENT_USER AS VARCHAR(10)) AS 'Who am i',* FROM dbo.v_employeeinfo_forManager WITH(NOLOCK) GO查詢結果展示如下,測試結果再次與預期吻合。
Employee權限測試
預期是employee沒有基表權限,沒有CEO視圖查看權限,也沒有Manager視圖查詢權限,只能看到employee層級數據,也就是會返回一條數據。
--Employee query test USE test GO--Employee cann't read data from basic table SELECT * FROM dbo.tb_Test_ViewPermission WITH(NOLOCK)--Employee can't read the data from CEO group SELECT * FROM v_employeeinfo_forCEO WITH(NOLOCK) GO--Employee can't read data from manager group SELECT CAST(CURRENT_USER AS VARCHAR(10)) AS 'Who am i',* FROM dbo.v_employeeinfo_forManager WITH(NOLOCK) GO--Employee just can read data from employee group SELECT CAST(CURRENT_USER AS VARCHAR(10)) AS 'Who am i',* FROM dbo.v_employeeinfo_forEmployee WITH(NOLOCK) GO結果顯示如下,employee層級測試結果也完全滿足預期。
寫在最后
從測試結果來看,SQL Server使用視圖來做權限控制方法是相當的清爽和徹底滿足老鳥預期的。于是菜鳥得意洋洋的來到老鳥辦公室,霸氣的展示了自己的解決方案和例子,老鳥覺得非常滿意。
總結
以上是生活随笔為你收集整理的SQL Server使用视图做权限控制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [C#] 简单的 Helper 封装 -
- 下一篇: MySQL 临时表