Sql-Server

如何添加有權訪問單個視圖的使用者?

  • March 11, 2016

我正在使用 MSSQL Server Management Studio 2008,我需要向第三方公開視圖以進行數據協調。我已經創建了適當的視圖,但在創建使用者和授予該使用者適當的權限以從視圖中選擇時遇到問題。

我按照嚮導創建了登錄名和使用者,然後在 Securables 部分中添加了我的視圖,並選中了授權框以進行選擇。一切似乎都很好,但是當我以該使用者身份登錄並嘗試執行“從 MyViewName 中選擇 *”時,它告訴我選擇權限被拒絕。

我剛剛重新創建了使用者(這次只是使用 SQL 而不是嚮導)並明確授予了選擇權限,現在它給了我錯誤:(Msg 916, Level 14, State 1, Line 2 The server principal "username" is not able to access the database "unrelated_db" under the current security context.我不知道為什麼它試圖訪問不相關的數據庫……)

我真的不知道從這裡去哪裡。同樣,基本上我只需要創建一個使用者,我可以將其提供給第三方,讓他們連接到我們的數據庫並從此視圖中進行選擇。

請不要為此使用 UI。這是一個令人困惑的混亂。

在我看來,您想要的是在數據庫中為特定登錄創建一個使用者,該使用者只有從一個視圖中選擇的權限。因此,由於您已經創建了登錄名:

USE your_db;
GO
CREATE USER username FROM LOGIN username;
GO
GRANT SELECT ON dbo.MyViewName TO username;
GO

這裡的編輯是一個腳本範例,它會導致您提到的錯誤。

首先,在 unrelated_db 中創建一些表:

CREATE DATABASE unrelated_db;
GO
USE unrelated_db;
GO
CREATE TABLE dbo.foo(bar INT);
GO

現在創建一個相對受限的登錄:

USE [master];
GO
CREATE LOGIN username WITH PASSWORD='foo', CHECK_POLICY = OFF;
GO

現在創建一個視圖所在的數據庫,並將登錄名添加為使用者:

CREATE DATABASE velojason;
GO
USE velojason;
GO
CREATE USER username FROM LOGIN username;
GO

現在創建一個函式來引用另一個數據庫中的表,以及另一個表的同義詞:

CREATE FUNCTION dbo.checkbar()
RETURNS INT
AS 
BEGIN
   RETURN 
   (
     SELECT TOP (1) bar 
       FROM unrelated_db.dbo.foo 
       ORDER BY bar
   );
END
GO
CREATE SYNONYM dbo.foo FOR unrelated_db.dbo.foo;
GO

現在創建一個本地表:

CREATE TABLE dbo.PaymentDetails
(
 PaymentID INT
);
GO

現在創建一個引用表、函式和同義詞的視圖,並SELECT授予username

CREATE VIEW dbo.SomeView
AS
 SELECT 
   p.PaymentID, 
   x = dbo.checkbar(), -- function that pulls from other DB
   y = (SELECT bar FROM dbo.foo) -- synonym to other DB
   FROM dbo.PaymentDetails AS p;
GO
GRANT SELECT ON dbo.SomeView TO username;
GO

現在嘗試執行 asusername並從視圖中僅選擇本地列:

EXECUTE AS USER = 'username';
GO
 -- even though I don't reference any of the columns 
 -- in the other DB, I am denied SELECT on the view:
SELECT PaymentID FROM dbo.SomeView;
GO
REVERT;
GO

結果:

消息 916,級別 14,狀態 1,第 3 行
伺服器主體“使用者名”無法在目前安全上下文下訪問數據庫“unrelated_db”。

現在將視圖更改為不引用任何外部對象,然後SELECT再次執行上面的程式碼,它就可以工作了:

ALTER VIEW dbo.SomeView
AS
 SELECT 
   p.PaymentID 
   --x = dbo.checkbar(),
   --y = (SELECT bar FROM dbo.foo)
   FROM dbo.PaymentDetails AS p;
GO

如果沒有向我們展示 Payment Details、Account Details 和 MyView 對象的腳本,也許您可以讓我們知道此查詢是否返回任何結果。您可以通過目錄視圖找到對各種對象的引用sys.sql_expression_dependencies,但是這個視圖並不完美 - 我相信它取決於所有被刷新的視圖(例如,在視圖引用其他視圖的情況下,或者底層架構發生了變化)要準確。

DECLARE 
 @dbname   SYSNAME = N'unrelated_db',
 @viewname SYSNAME = N'dbo.SomeView';

SELECT DISTINCT 
   [This object] = 
   OBJECT_SCHEMA_NAME([referencing_id]) 
     + '.' + OBJECT_NAME([referencing_id]), 
   [references this object] = 
   OBJECT_SCHEMA_NAME([referenced_id]) 
     + '.' + OBJECT_NAME([referenced_id]), 
   [and touches this database] = referenced_database_name,
   [and is a(n)] = o.type_desc,
   [if synonym, it references] = s.base_object_name
FROM sys.sql_expression_dependencies AS d
LEFT OUTER JOIN sys.objects AS o
ON o.[object_id] = d.referenced_id
LEFT OUTER JOIN sys.synonyms AS s
ON d.referenced_id = s.[object_id]
AND s.base_object_name LIKE '%[' + @dbname + ']%'
WHERE OBJECT_ID(@viewname) IN (
       referenced_id, 
       referencing_id, 
       (SELECT referencing_id FROM sys.sql_expression_dependencies 
       WHERE referenced_database_name = @dbname)
) OR referenced_database_name = @dbname;

SQL Server 不只是為了獲得unrelated_db樂趣而嘗試訪問…從您嘗試使用的視圖來看,該數據庫必須與該數據庫有某種聯繫。不幸的是,如果我們看不到視圖定義和它所接觸的對象的更多細節,我們所能做的就是推測。我能想到的兩個主要事情是使用三部分名稱的同義詞或函式,但是查看實際腳本會給我們一個更好的主意,而不是猜測。:-)

您可能還想檢查sys.dm_sql_referenced_entities,但是此函式在上面的範例中沒有返回任何有用的資訊。

create login YourTpvLogin with password = 'enter new password here'
go

use SomeDb
go

create user YourTpvUser for login YourTpvLogin
go

grant select on YourView to YourTpvUser
go

您可以通過執行以下操作來測試它:

execute as user = 'YourTpvUser'
go

select *
from YourView

revert
go

引用自:https://dba.stackexchange.com/questions/17177