Wie füge ich einen Benutzer mit Zugriff auf eine einzelne Ansicht hinzu?

14

Ich arbeite mit MSSQL Server Management Studio 2008 und muss die Ansicht für die Datenabstimmung einem Dritten zur Verfügung stellen. Ich habe die entsprechende Ansicht erstellt, kann jedoch keinen Benutzer erstellen und diesem Benutzer die erforderlichen Berechtigungen zum Auswählen in der Ansicht erteilen.

Ich folgte den Assistenten zum Erstellen eines Anmeldenamens und eines Benutzers und fügte dann meine Ansicht im Abschnitt "Sicherheit" hinzu, wobei das Kontrollkästchen "Gewähren" für "Auswählen" aktiviert war. Alles schien in Ordnung zu sein, aber als ich mich als dieser Benutzer anmeldete und versuchte, "Select * from MyViewName" auszuführen, wurde mir mitgeteilt, dass die Auswahlberechtigung verweigert wurde.

Ich habe den Benutzer gerade neu erstellt (diesmal nur mit SQL anstelle des Assistenten) und explizit Auswahlberechtigungen erteilt. Jetzt erhalte ich den Fehler: 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. (Ich weiß nicht, warum versucht wird, auf die nicht verknüpfte Datenbank zuzugreifen ...)

Ich weiß wirklich nicht, wohin ich von hier aus gehen soll. Auch hier muss ich im Grunde nur einen Benutzer erstellen, den ich dem Dritten geben kann, damit dieser eine Verbindung zu unserer Datenbank herstellt und aus dieser Ansicht auswählt.

velojason
quelle
3
Verweist die Ansicht auf Basistabellen in anderen Datenbanken? In diesem Fall müssen Sie sich mit der Verkettung von Eigentumsrechten befassen. Stellen Sie außerdem sicher, dass der Datenbankkontext aktuell auf die gewünschte Datenbank eingestellt ist.
Thomas Stringer
Gibt es eine Möglichkeit, die Abhängigkeiten für eine Ansicht anzuzeigen? Ich meine, soweit ich weiß, alles aus der Sicht sollte in der Hauptdatenbank enthalten sein. Die Ansicht besteht nur aus drei Feldern, von denen zwei aus einer Tabelle mit Zahlungsdetails und eines aus einem Join mit der Tabelle mit den Kontodetails stammen. Beide Tabellen befinden sich jedoch in derselben Datenbank (und in derselben Datenbank wie die Ansicht).
Velojason

Antworten:

16

Bitte benutzen Sie hierfür nicht die Benutzeroberfläche. Es ist ein verwirrendes Durcheinander.

Es hört sich für mich so an, als ob Sie einen Benutzer in einer Datenbank für ein bestimmtes Login erstellen möchten, der nur die Berechtigung hat, aus einer Ansicht auszuwählen. Also, da Sie bereits das Login erstellt haben:

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

BEARBEITEN hier ein Beispiel für ein Skript, das zu dem von Ihnen genannten Fehler führt.

Erstellen Sie zunächst eine Tabelle in der unrelated_db:

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

Erstellen Sie jetzt ein relativ eingeschränktes Login:

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

Erstellen Sie nun eine Datenbank, in der die Ansicht gespeichert wird, und fügen Sie die Anmeldung als Benutzer hinzu:

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

Erstellen Sie nun eine Funktion, die auf die Tabelle in der anderen Datenbank verweist, und ein Synonym für die andere Tabelle:

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

Erstellen Sie nun eine lokale Tabelle:

CREATE TABLE dbo.PaymentDetails
(
  PaymentID INT
);
GO

Erstellen Sie nun eine Ansicht , die Referenzen der Tabelle, die Funktion und das Synonym und Erteilung SELECTzu 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

Versuchen Sie nun, als auszuführen usernameund wählen Sie nur die lokale Spalte aus der Ansicht aus:

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

Ergebnis:

Meldung 916, Ebene 14, Status 1, Zeile 3
Der Serverprinzipal "Benutzername" kann im aktuellen Sicherheitskontext nicht auf die Datenbank "unrelated_db" zugreifen.

Ändern Sie nun die Ansicht so, dass keine externen Objekte referenziert werden, und führen Sie die obigen Schritte SELECTerneut aus.

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

Sie können uns nicht nur die Skripte für die Zahlungsdetails, Kontodetails und MyView-Objekte anzeigen, sondern auch mitteilen, ob diese Abfrage Ergebnisse liefert. Sie können Verweise auf verschiedene Objekte über die Katalogansicht finden sys.sql_expression_dependencies, aber diese Ansicht ist nicht perfekt - ich glaube, es hängt davon ab, dass alle Ansichten aktualisiert werden (falls sich Ansichten beispielsweise auf andere Ansichten beziehen oder das zugrunde liegende Schema geändert hat) um genau zu sein.

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 wird nicht nur versuchen, darauf zuzugreifen unrelated_db Spaß Es muss eine Verbindung zu dieser Datenbank in der Ansicht bestehen, die Sie verwenden möchten. Leider können wir nur spekulieren, wenn wir die Ansichtsdefinition und weitere Details zu den Objekten, die sie berührt, nicht sehen können. Die beiden wichtigsten Dinge, an die ich denken kann, sind Synonyme oder Funktionen, die dreiteilige Namen verwenden. Wenn wir jedoch die tatsächlichen Skripte sehen, erhalten wir eine viel bessere Vorstellung, anstatt zu raten. :-)

Möglicherweise möchten Sie auch überprüfen sys.dm_sql_referenced_entities, aber diese Funktion gibt im obigen Beispiel nichts Nützliches zurück.

Aaron Bertrand
quelle
6
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

Sie können dies folgendermaßen testen:

execute as user = 'YourTpvUser'
go

select *
from YourView

revert
go
Thomas Stringer
quelle
Anscheinend gewährt dies nicht rekursiv Privilegien. Der Benutzer kann aus "YourView" auswählen, aber wenn "YourView" von anderen Beziehungen / Datenbanken abhängt, schlägt dies fehl: Der Serverprinzipal "YourTpvUser" kann im aktuellen Sicherheitskontext nicht auf die Datenbank "OtherDb" zugreifen.
Lilalinux