SQL Server: przyznaj dostęp użytkownikowi w widoku, a nie w jego tabelach

11

Mam wystąpienie programu SQL Server 2012 z kilkoma bazami danych. W jednym z nich stworzyłem widok, który wybiera tabele w więcej niż bazie danych.

Chcę, aby użytkownik mógł wybrać ten widok, ale nie może wybierać swoich tabel. Widok został utworzony dokładnie dlatego, że użytkownik nie może wybrać tabel.

Przeczytałem /programming/368414/grant-select-on-a-view-not-base-table i http://msdn.microsoft.com/en-us/library/ms188676. aspx i nadal nie działa.

Jeśli zrobię a GRANT SELECT TABLE TO USERdla wszystkich tabel, użytkownik może wybrać widok. Ale jeśli odwołam do dowolnego stołu, nie powiedzie się.

To powinna być łatwa procedura, ale mam problem z jej uruchomieniem. Widziałem to wcześniej (właściciel instancji dał mi dostęp do widoku i nie zrobił tego z tabelami), ale nie jestem w stanie tego zrobić ani znaleźć kogoś, kto wie jak.

Czy ktoś mógłby mi dostarczyć tutorial, jak to zrobić, lub przykład kodu?


Gdy użytkownik SELECTswyświetli widok, dostaję komunikat:

Odmówiono uprawnienia SELECT do obiektu <TABLE>, bazy danych <DB>, schematu dbo.

Jeśli udzielę zaznaczenia tej tabeli, komunikat o błędzie zmieni nazwę tabeli na inną tabelę odczytaną przez widok.

Hikari
źródło
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Paul White 9

Odpowiedzi:

21

Jeśli chcesz, aby użytkownicy wybierali z widoku, dlaczego udzielasz tabeli? Przez „odwołanie” masz na myśli wprost odwołanie / odrzucenie? Odmowa zastąpi grant, więc jest twój problem ... powinieneś być w stanie to zrobić, dodając grant do widoku i nie robiąc nic w żaden sposób na stołach.

Oto szybki przykład, w którym SELECTnie podano wyraźnie tabeli, ale widok. Użytkownik może wybrać z widoku, ale nie z tabeli.

CREATE USER foo WITHOUT LOGIN;
GO
CREATE TABLE dbo.a(id INT);
CREATE TABLE dbo.b(id INT);
GO
CREATE VIEW dbo.v 
AS 
  SELECT a.id FROM a INNER JOIN b ON a.id = b.id;
GO
GRANT SELECT ON dbo.v TO foo;
GO
EXECUTE AS USER = N'foo';
GO
-- works:
SELECT id FROM dbo.v;
GO
-- Msg 229, SELECT denied:
SELECT id FROM dbo.a;
GO
REVERT;

Należy pamiętać, że zakłada to, że foonie przyznano podwyższonych uprawnień poprzez wyraźne uprawnienia do schematu lub bazy danych, ani poprzez członkostwo w roli lub grupie.

Ponieważ używasz tabel w wielu bazach danych (przepraszam, początkowo brakowało mi końca pierwszego zdania), możesz również potrzebować wyraźnych przydziałów dla tabel w bazie danych, w których widok nie istnieje. Aby uniknąć przyznawania wyboru tabelom, możesz utworzyć widok w każdej bazie danych, a następnie dołączyć widoki.

Utwórz dwie bazy danych i login:

CREATE DATABASE d1;
GO
CREATE DATABASE d2;
GO
USE [master];
GO
CREATE LOGIN blat WITH PASSWORD = 'x', CHECK_POLICY = OFF;
GO

W bazie danych d1utwórz użytkownika, a następnie utwórz tabelę i prosty widok dla tej tabeli. Przyznaj użytkownikowi wybór tylko w stosunku do widoku:

USE d1;
GO
CREATE USER blat FROM LOGIN blat;
GO
CREATE TABLE dbo.t1(id INT);
GO
CREATE VIEW dbo.v1
AS
  SELECT id FROM dbo.t1;
GO
GRANT SELECT ON dbo.v1 TO blat;
GO

Teraz w drugiej bazie danych utwórz użytkownika, a następnie utwórz kolejną tabelę i widok, który łączy tę tabelę z widokiem w d1. Przyznaj zaznacz tylko do widoku.

USE d2;
GO
CREATE USER blat FROM LOGIN blat;
GO
CREATE TABLE dbo.t2(id INT);
GO
CREATE VIEW dbo.v2
AS
  SELECT v1.id FROM dbo.t2 
    INNER JOIN d1.dbo.v1 AS v1
    ON t2.id = v1.id;
GO
GRANT SELECT ON dbo.v2 TO blat;
GO

Teraz uruchom nowe okno zapytania i zmień dane logowania do logowania blat( EXECUTE AStutaj nie działa). Następnie uruchom następujące polecenie w kontekście dowolnej bazy danych i powinno działać dobrze:

SELECT id FROM d1.dbo.v2;

Oba powinny przynieść błędy Msg 229:

SELECT id FROM d1.dbo.t1;
GO
SELECT id FROM d2.dbo.t2;

Wyniki:

Msg 229, poziom 14, stan 5, wiersz 1
Odmówiono uprawnienia SELECT do obiektu „t1”, bazy danych „d1”, schematu „dbo”.
Msg 229, poziom 14, stan 5, wiersz 3
Odmówiono uprawnienia SELECT do obiektu „t2”, bazy danych „d2”, schematu „dbo”.

Aaron Bertrand
źródło
1

Odpowiedź wiki społeczności pierwotnie dodana do pytania przez autora:

Oto co zrobiłem:

  1. Utworzono widok w DB A, łącząc wszystkie tabele w nim.
  2. Przyznaj SELECTdostęp użytkownikowi w tym widoku, a NIE żadnej z jego tabel. Użytkownikowi udało się wykonać zapytanie dotyczące widoku, a nie tabel.
  3. Utworzono widok w DB B, łącząc tabele w tym DB razem z widokiem w DB A.
  4. Udzielono użytkownikowi SELECTdostępu do tego drugiego widoku, a także NIE do żadnej tabeli. Użytkownik mógł pomyślnie wysłać zapytanie do tego ostatecznego widoku i zobaczyć dane.

Myślę, że to dziwne, że widok może wyszukiwać tabele w swojej bazie danych, że użytkownik nie ma bezpośredniego dostępu, ale nie może tego zrobić w tabelach z innej bazy danych. Przynajmniej zadziałało.

użytkownik126897
źródło