當數據庫越來越多,連接到數據庫的應用程序,服務器,賬號越來越多的時候,為了既能達到滿足賬號操作數據權限需求,又不擴大其操作權限,保證數據庫的安全性,有時候需要用角色來參與到權限管理中,通過角色做一個權限與訪問用不之前的映射,可以更加方便地管理權限。
USE master GO --創建一個用戶 CREATE LOGIN ReadUser WITH PASSWORD ='123qwe!@#',DEFAULT_DATABASE=DBTest USE DBTest GO --創建用戶,指定到上面 CREATE USER ReadUser FOR LOGIN ReadUser WITH DEFAULT_SCHEMA = dbo
用SETUSER 切換到上面建的ReadUser賬號下面,通過print Session_user發現已經切換到了ReadUser,以ReadUser的身份執行一個查詢,
此時提示ReadUser沒有DetailTable的SELECT 權限
以管理員身份授權給ReadUser查詢dbo.DetailTable表的權限
再次以ReadUser的身份執行上述查詢,這次發現可以正常執行了
如果允許ReadUser這個賬號對當前庫多張表都要有查詢的全新,就要將GRANT SELECT ON TableName重復N次,
那么問題就來了,如果此時需要再建一個同樣權限的用戶,ReadUser2,授予同樣的權限,又要重復N此GRANT操作?
此時就需要借助角色這一數據庫對象來管理權限,將User加入到某一個角色中,來避免每次新增一個User都要執行一遍授權操作。
首先用管理員權限創建一個角色ReadRole
然后依次執行如下操作,將之前授權給ReadUser的權限給Revoke掉,
1,新建一個名稱為ReadRole的角色
2,將多張表的查詢權限授予ReadRole這一角色
3,將User加入到這個角色中
執行完成之后,我們在來嘗試UserRead這個角色的權限,可以發現:角色有的權限,ReadUser也都有了
如果此時再新建一個ReadUser2
此時切換到ReadUser2的身份下,發現ReadUser2也具備了ReadRole這個自定義角色的權限
上述的ReadRole是自定義的角色,上面給他授權的是當前數據庫中的部分表的SELECT權限
如果需要全庫的所有表的SELECT權限,就可以借助DataBase Role來實現了,將用戶加入到DataBase級別的db_dataReader這個角色中
如下截圖
DataBase級別的角色作用范圍是整個DB的,比如db_datareader,db_datawriter都是作用在數據庫所有的對象
對於這種范圍比較大而不適合使用的場景,就可以采用類似上述自定義角色,通過給角色授予指定范圍內的權限的方式來實現用戶權限管理
角色不僅可以在表上做權限控制和管理,也可以管理視圖(查詢),存儲過程(執行),函數(查詢),Sequence(Sequence是Update)等對象上的操作權限,通過授權給角色權限,把某一列用戶加入到某一個角色中,用角色來管理用戶和數據庫對象之間的權限管理,可以做到更加統一地管理權限。
最后,附上兩個腳本
1.查詢某個角色擁有哪些權限
--查詢某個角色擁有的權限 select USER_NAME(p.grantee_principal_id) AS principal_name, dp.principal_id, dp.type_desc AS principal_type_desc, p.class_desc, OBJECT_NAME(p.major_id) AS object_name, p.permission_name, p.state_desc AS permission_state_desc from sys.database_permissions p INNER JOIN sys.database_principals dp on p.grantee_principal_id = dp.principal_id where USER_NAME(p.grantee_principal_id) = 'ReadRole' --角色名稱
2.查詢某個User有哪些角色的權限(User屬於哪一個(多個)角色)
--某個User有哪些角色的權限(User屬於哪一個(多個)角色) SELECT u.name, r.name FROM sys.database_role_members AS m INNER JOIN sys.database_principals AS r ON m.role_principal_id = r.principal_id INNER JOIN sys.database_principals AS u ON u.principal_id = m.member_principal_id WHERE u.name = 'ReadUser'; --UserName
3.查詢某個賬號有哪些權限,直接授權給賬號的,而不是通過角色繼承來的
--查詢某個賬號有哪些權限,直接授權給賬號的,而不是通過角色繼承來的 select USER_NAME(p.grantee_principal_id) AS principal_name, p.grantee_principal_id, dp.principal_id, dp.type_desc AS principal_type_desc, p.class_desc, OBJECT_NAME(p.major_id) AS object_name, p.permission_name, p.state_desc AS permission_state_desc from sys.database_permissions p INNER JOIN sys.database_principals dp on p.grantee_principal_id = dp.principal_id where USER_NAME(p.grantee_principal_id) = 'ReadUser'
4.查詢一個UserName擁有的所有權限(通過角色集成的權限和自身具備的權限)
--查詢一個UserName擁有的角色以及角色擁有的操作對象 DECLARE @login_name varchar(100) = 'XXX' ;WITH LoginName AS ( SELECT u.name AS LoginName, r.name AS RoleName, role_principal_id AS PrincipalId FROM sys.database_role_members AS m INNER JOIN sys.database_principals AS r ON r.principal_id = m.role_principal_id INNER JOIN sys.database_principals AS u ON u.principal_id = m.member_principal_id ), UserPermission AS ( select USER_NAME(p.grantee_principal_id) AS principal_name, dp.principal_id AS principal_id, dp.type_desc AS principal_type_desc, p.class_desc AS class_desc, OBJECT_NAME(p.major_id) AS object_name, p.permission_name AS permission_name, p.state_desc AS permission_state_desc from sys.database_permissions p INNER JOIN sys.database_principals dp on p.grantee_principal_id = dp.principal_id ) SELECT * FROM ( --通過角色獲取的權限對象 SELECT u.LoginName, u.RoleName, p.principal_type_desc, p.class_desc, p.permission_name, p.object_name, p.permission_state_desc FROM LoginName u left join UserPermission p on p.principal_name = u.RoleName WHERE u.LoginName = @login_name UNION ALL --直接授權給賬號的權限對象 select @login_name AS LoginName, '' AS RoleName, dp.type_desc AS principal_type_desc, p.class_desc AS class_desc, p.permission_name AS permission_name, OBJECT_NAME(p.major_id) AS object_name, p.state_desc AS permission_state_desc from sys.database_permissions p INNER JOIN sys.database_principals dp on p.grantee_principal_id = dp.principal_id where USER_NAME(p.grantee_principal_id) = @login_name UNION ALL --固定服務器角色的權限 SELECT r.name , cast(r.principal_id as varchar(10)) , r.type_desc, null as class_desc, null as object_name, p2.name as permission_name, null as permission_state_desc FROM sys.server_principals r INNER JOIN sys.server_role_members m ON r.principal_id = m.member_principal_id INNER JOIN sys.server_principals p1 ON p1.principal_id = m.member_principal_id INNER JOIN sys.server_principals p2 ON p2.principal_id = m.role_principal_id WHERE r.name = @login_name )t