SQL Server: conceda acceso selecto a un usuario en una vista y no en sus tablas

11

Tengo una instancia de SQL Server 2012 con algunas bases de datos. En uno de ellos creé una vista, que selecciona tablas en más de una base de datos.

Quiero que un usuario pueda seleccionar esa vista, pero no debe seleccionar sus tablas. La vista se creó exactamente porque el usuario no puede seleccionar las tablas.

He leído /programming/368414/grant-select-on-a-view-not-base-table y http://msdn.microsoft.com/en-us/library/ms188676. aspx y todavía no funciona.

Si hago una GRANT SELECT TABLE TO USERa todas las tablas, el usuario puede seleccionar la vista. Pero si revoco a cualquier tabla, falla.

Este debería ser un procedimiento fácil de hacer, pero tengo problemas para que funcione. Lo he visto suceder antes (el propietario de una instancia me dio acceso a una vista y no lo hizo en sus tablas), pero no puedo hacerlo o encontrar a alguien que sepa cómo hacerlo.

¿Podría alguien proporcionarme un tutorial sobre cómo hacerlo, o un ejemplo de código?


Cuando el usuario SELECTsla ve me sale el mensaje:

El permiso SELECT fue denegado en el objeto <TABLE>, base de datos <DB>, esquema dbo.

Si otorgo select a esa tabla, el mensaje de error cambia el nombre de la tabla a otra tabla que la vista lee.

Hikari
fuente
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Paul White 9

Respuestas:

21

Si desea que los usuarios seleccionen desde la vista, ¿por qué está otorgando a la tabla? Por "revocar", ¿quiere decir explícitamente revocar / negar? Denegar anulará la concesión, por lo que está su problema ... debería poder lograr esto agregando concesión a la vista y no haciendo nada de ninguna manera en las tablas.

Aquí hay un ejemplo rápido en el que SELECTno se ha otorgado explícitamente en la tabla, pero sí en la vista. El usuario puede seleccionar desde la vista pero no desde la tabla.

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;

Tenga en cuenta que esto supone que foono se le han otorgado privilegios elevados a través de permisos explícitos en el esquema o la base de datos, o mediante la pertenencia a roles o grupos.

Como está utilizando tablas en varias bases de datos (lo siento, me perdí el final de esa primera oración inicialmente), también puede necesitar concesiones explícitas en las tablas en la base de datos donde la vista no existe. Para evitar otorgar selección a las tablas, puede crear una vista en cada base de datos y luego unir las vistas.

Cree dos bases de datos y un inicio de sesión:

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

En la base de datos d1, cree un usuario, luego cree una tabla y una vista simple contra esa tabla. Otorgue selección al usuario solo contra la vista:

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

Ahora, en la segunda base de datos, cree el usuario, luego cree otra tabla y una vista que una esa tabla a la vista d1. Otorgue selección solo a la vista.

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

Ahora inicie una nueva ventana de consulta y cambie las credenciales para iniciar sesión blat( EXECUTE ASno funciona aquí). Luego ejecute lo siguiente desde el contexto de cualquiera de las bases de datos, y debería funcionar bien:

SELECT id FROM d1.dbo.v2;

Ambos deberían producir errores Msg 229:

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

Resultados:

Mensaje 229, Nivel 14, Estado 5, Línea 1
El permiso SELECT fue denegado en el objeto 't1', base de datos 'd1', esquema 'dbo'.
Mensaje 229, Nivel 14, Estado 5, Línea 3
El permiso SELECT fue denegado en el objeto 't2', base de datos 'd2', esquema 'dbo'.

Aaron Bertrand
fuente
1

Respuesta wiki de la comunidad originalmente agregada a la pregunta por su autor:

Esto es lo que hice:

  1. Creó una vista en DB A, uniendo todas las tablas en ella.
  2. SELECTAcceso otorgado al usuario en esa vista, y NO a ninguna de sus tablas. El usuario pudo consultar con éxito la vista y no las tablas.
  3. Creó una vista en DB B, uniendo tablas en este DB junto con la vista en DB A.
  4. SELECTAcceso otorgado al usuario en esta segunda vista, y NO a ninguna tabla. El usuario pudo consultar con éxito esta vista final y ver los datos.

Creo que es extraño que una vista pueda consultar tablas en su DB que el usuario no tiene acceso directo pero no puede hacerlo en tablas de otro DB. Al menos funcionó.

usuario126897
fuente