Как добавить пользователя с доступом к одному представлению?

14

Я работаю с 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.(Я не знаю, почему он пытается получить доступ к несвязанной базе данных ...)

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

velojason
источник
3
Есть ли ссылки на базовые таблицы в других базах данных? Если это так, вам придется иметь дело с цепочкой владения. Кроме того, убедитесь, что у вас в настоящее время установлен контекст базы данных для нужной базы данных.
Томас Стрингер,
Есть ли способ увидеть зависимости для представления? Я имею в виду, насколько я знаю, все из представления должно содержаться в основной базе данных. Представление состоит из трех полей: два из таблицы данных о платеже и одно из соединения с таблицей сведений об учетной записи, но обе таблицы находятся в одной базе данных (и той же базе данных, что и представление).
Velojason

Ответы:

16

Пожалуйста, не используйте пользовательский интерфейс для этого. Это запутанный беспорядок.

Для меня это звучит так, как будто вы хотите создать пользователя в базе данных для конкретного входа в систему, у которого есть только права на выбор из одного представления. Итак, поскольку вы уже создали логин:

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

Теперь попробуйте выполнить как usernameи выберите только локальный столбец из представления:

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

Если не считать сценариев для объектов «Платежная информация», «Сведения о счете» и «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, однако эта функция не возвращает ничего полезного в примере выше.

Аарон Бертран
источник
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

Вы можете проверить это, выполнив следующие действия:

execute as user = 'YourTpvUser'
go

select *
from YourView

revert
go
Томас Стрингер
источник
Очевидно, это не дает рекурсивных привилегий. Пользователю разрешено выбирать из «YourView», но если «YourView» зависит от других отношений / баз данных, произойдет сбой: основной сервер «YourTpvUser» не может получить доступ к базе данных «OtherDb» в текущем контексте безопасности.
lilalinux