Jak dodać użytkownika z dostępem do jednego widoku?

14

Pracuję z MSSQL Server Management Studio 2008 i muszę ujawnić widok stronom trzecim w celu uzgodnienia danych. Utworzyłem odpowiedni widok, ale mam problem z utworzeniem użytkownika i nadaniem mu odpowiednich uprawnień do wyboru z tego widoku.

Postępowałem zgodnie z instrukcjami kreatorów, aby utworzyć login i użytkownika, a następnie dodałem mój widok w sekcji Zabezpieczenia z zaznaczonym polem przyznania. Wszystko wydawało się w porządku, ale kiedy zalogowałem się jako ten użytkownik i spróbowałem zrobić „Wybierz * z MyViewName”, powiedziało mi, że odmówiono zgody na wybór.

Właśnie odtworzyłem użytkownika (tym razem używając SQL zamiast kreatora) i wyraźnie przyznałem uprawnienia do wybierania, a teraz daje mi błąd: 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.(Nie wiem, dlaczego próbuje uzyskać dostęp do niepowiązanej bazy danych ...)

Naprawdę nie wiem stąd, gdzie mam iść. Ponownie, w zasadzie wszystko, czego potrzebuję, to stworzyć użytkownika, który mogę przekazać stronie trzeciej, aby mógł połączyć się z naszą bazą danych i wybrać z tego widoku.

Velojason
źródło
3
Czy widok odwołuje się do bazowych tabel w innych bazach danych? Jeśli tak, będziesz musiał poradzić sobie z łańcuchem własności. Upewnij się także, że kontekst bazy danych jest ustawiony na żądaną bazę danych.
Thomas Stringer
Czy jest jakiś sposób, aby zobaczyć zależności dla widoku? O ile mi wiadomo, wszystko z widoku powinno być zawarte w głównej bazie danych. Widok to tylko trzy pola, dwa pochodzące z tabeli szczegółów płatności i jedno pochodzące z przyłączenia do tabeli szczegółów konta, ale obie tabele znajdują się w tej samej bazie danych (i tej samej bazie danych, co widok).
velojason

Odpowiedzi:

16

Nie używaj do tego interfejsu użytkownika. To mylący bałagan.

Wydaje mi się, że chcesz utworzyć użytkownika w bazie danych dla określonego loginu, który ma uprawnienia tylko do wyboru z jednego widoku. Skoro masz już utworzone dane logowania:

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

EDYCJA tutaj jest przykładem skryptu, który doprowadzi do wspomnianego błędu.

Najpierw utwórz tabelę w unrelated_db:

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

Teraz utwórz względnie ograniczony login:

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

Teraz utwórz bazę danych, w której będzie wyświetlany widok, i dodaj login jako użytkownik:

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

Teraz utwórz funkcję, która będzie odwoływać się do tabeli w innej bazie danych, i synonim do drugiej tabeli:

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

Teraz utwórz lokalny stół:

CREATE TABLE dbo.PaymentDetails
(
  PaymentID INT
);
GO

Teraz utworzyć widok, że odniesienia do stołu, funkcja i synonim, a dotacje SELECTdo 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

Teraz spróbuj wykonać jako usernamei wybierz tylko lokalną kolumnę z widoku:

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

Wynik:

Msg 916, poziom 14, stan 1, wiersz 3
Główna nazwa serwera „nazwa użytkownika” nie może uzyskać dostępu do bazy danych „unrelated_db” w obecnym kontekście bezpieczeństwa.

Teraz zmień widok, aby nie odwoływał się do żadnych obiektów zewnętrznych, i uruchom SELECTponownie powyższe , i to działa:

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

Zamiast pokazywania nam skryptów dla szczegółów płatności, szczegółów konta i obiektów MyView, może możesz dać nam znać, jeśli to zapytanie zwróci jakiekolwiek wyniki. Można znaleźć odniesienia do różnych obiektów za pośrednictwem widoku katalogu sys.sql_expression_dependencies, ale ten widok nie jest idealny - uważam, że zależy to od odświeżenia wszystkich widoków (w przypadku, gdy widoki odwołują się na przykład do innych widoków lub do zmieniającego się schematu) w kolejności być punktualnym.

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 nie będzie próbował uzyskać dostępu tylko unrelated_dbdla zabawy ... musi istnieć pewien związek z tą bazą danych z widoku, którego próbujesz użyć. Niestety, jeśli nie widzimy definicji widoku i więcej szczegółów na temat dotykanych przez nią obiektów, możemy jedynie spekulować. Dwie główne rzeczy, o których myślę, to synonimy lub funkcje, które używają trzech części, ale zobaczenie rzeczywistych skryptów da nam znacznie lepszy pomysł, niż zgadywanie. :-)

Możesz także chcieć to sprawdzić sys.dm_sql_referenced_entities, jednak funkcja ta nie zwraca nic użytecznego w powyższym przykładzie.

Aaron Bertrand
źródło
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

Możesz to sprawdzić, wykonując następujące czynności:

execute as user = 'YourTpvUser'
go

select *
from YourView

revert
go
Thomas Stringer
źródło
Najwyraźniej nie przyznaje to rekurencyjnie uprawnień. Użytkownik może wybrać opcję „YourView”, ale jeśli „YourView” zależy od innych relacji / baz danych, to się nie powiedzie: Główny serwer „YourTpvUser” nie może uzyskać dostępu do bazy danych „OtherDb” w bieżącym kontekście bezpieczeństwa.
lilalinux