SQL Server: предоставить выборочный доступ пользователю в представлении, а не в его таблицах

11

У меня есть экземпляр SQL Server 2012 с несколькими базами данных. В одном из них я создал представление, которое выбирает таблицы больше, чем база данных.

Я хочу, чтобы пользователь мог выбрать это представление, но он не должен выбирать свои таблицы. Представление было создано именно потому, что пользователь не может выбрать таблицы.

Я прочитал /programming/368414/grant-select-on-a-view-not-base-table и http://msdn.microsoft.com/en-us/library/ms188676. ASPX и до сих пор это не работает.

Если я сделаю GRANT SELECT TABLE TO USERвсе таблицы, пользователь сможет выбрать представление. Но если я отзовусь к любому столу, он потерпит неудачу.

Это должна быть простая процедура, но у меня проблемы с тем, чтобы она заработала. Я видел это раньше (владелец экземпляра дал мне доступ к представлению и не сделал его с его таблицами), но я не могу это сделать или найти кого-то, кто знает, как.

Может ли кто-нибудь предоставить мне учебник о том, как это сделать, или пример кода?


При просмотре пользователем SELECTsя получаю сообщение:

В доступе SELECT было отказано для объекта <TABLE>, базы данных <DB>, схемы dbo.

Если я предоставлю выбор этой таблице, сообщение об ошибке изменит имя таблицы на другую таблицу, которую читает представление.

Hikari
источник
Комментарии не для расширенного обсуждения; этот разговор был перенесен в чат .
Пол Уайт 9

Ответы:

21

Если вы хотите, чтобы пользователи выбирали из представления, почему вы предоставляете эту таблицу? Под «отзывать» вы подразумеваете явное «отозвать / отрицать»? Запрет будет отменять грант, так что есть ваша проблема ... вы должны быть в состоянии сделать это, добавив грант в представление и ничего не делая в любом случае с таблицами.

Вот быстрый пример, где SELECTявно не предоставлено на столе, но было на представлении. Пользователь может выбирать из вида, но не из таблицы.

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;

Обратите внимание, что это предполагает, fooчто не было предоставлено повышенных привилегий через явные разрешения на схему или базу данных, или через роль или членство в группе.

Поскольку вы используете таблицы в нескольких базах данных (извините, я пропустил конец первого предложения вначале), вам также могут потребоваться явные разрешения для таблиц в базе данных, где представление не существует. Чтобы избежать предоставления выбора таблицам, вы можете создать представление в каждой базе данных, а затем объединить представления.

Создайте две базы данных и логин:

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

В базе данных d1создайте пользователя, затем создайте таблицу и простое представление для этой таблицы. Предоставить пользователю право выбора только для просмотра:

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

Теперь, во второй базе данных, создайте пользователя, затем создайте другую таблицу и представление, которое присоединяет эту таблицу к представлению в d1. Предоставить выбор только для просмотра.

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

Теперь запустите новое окно запроса и измените учетные данные для входа в систему blat( EXECUTE ASздесь не работает). Затем запустите следующее из контекста любой базы данных, и оно должно работать нормально:

SELECT id FROM d1.dbo.v2;

Оба должны дать Msg 229 ошибок:

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

Результаты:

Сообщение 229, уровень 14, состояние 5, строка 1
Отказано в разрешении SELECT для объекта «t1», базы данных «d1», схемы «dbo».
Сообщение 229, уровень 14, состояние 5, строка 3
Отказано в разрешении SELECT для объекта «t2», базы данных «d2», схемы «dbo».

Аарон Бертран
источник
1

Сообщество вики-ответа изначально добавило на вопрос его автора:

Вот что я сделал:

  1. Создал представление в БД А, соединив все таблицы в нем.
  2. Предоставил SELECTдоступ пользователю в этом представлении, а не в любой из его таблиц. Пользователь успешно смог запросить представление, а не таблицы.
  3. Создал представление в БД B, соединив таблицы в этой БД вместе с представлением в БД A.
  4. Предоставил SELECTдоступ пользователю на этом втором представлении, а также НЕ к любой таблице. Пользователь успешно смог запросить этот окончательный вид и посмотреть данные.

Мне кажется странным, что представление может запрашивать таблицы в своей БД, что у пользователя нет прямого доступа, но он не может сделать это в таблицах из другой БД. По крайней мере, это сработало.

user126897
источник