SQL Server: accorder un accès sélectif à un utilisateur dans une vue et non dans ses tables

11

J'ai une instance SQL Server 2012 avec quelques bases de données. Dans l'un d'eux, j'ai créé une vue, qui sélectionne des tables dans plus d'une base de données.

Je veux qu'un utilisateur puisse sélectionner cette vue, mais il ne doit pas sélectionner ses tables. La vue a été créée exactement parce que l'utilisateur ne peut pas sélectionner les tables.

J'ai lu /programming/368414/grant-select-on-a-view-not-base-table et http://msdn.microsoft.com/en-us/library/ms188676. aspx et cela ne fonctionne toujours pas.

Si je fais un GRANT SELECT TABLE TO USERpour toutes les tables, l'utilisateur peut sélectionner la vue. Mais si je révoque une table, cela échoue.

Cela devrait être une procédure facile à faire, mais j'ai du mal à le faire fonctionner. Je l'ai déjà vu (le propriétaire d'une instance m'a donné accès à une vue et ne l'a pas fait à ses tables) mais je ne peux pas le faire ou trouver quelqu'un qui sait comment.

Quelqu'un pourrait-il me fournir un tutoriel sur la façon de le faire, ou un exemple de code?


Lorsque l'utilisateur SELECTsla vue, je reçois le message:

L'autorisation SELECT a été refusée sur l'objet <TABLE>, la base de données <DB>et le schéma dbo.

Si j'accorde select à cette table, le message d'erreur change le nom de la table en une autre table que la vue lit.

Hikari
la source
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
Paul White 9

Réponses:

21

Si vous souhaitez que les utilisateurs choisissent dans la vue, pourquoi accordez-vous à la table? Par «révoquer», voulez-vous dire explicitement révoquer / refuser? Le refus remplacera l'octroi, il y a donc votre problème ... vous devriez pouvoir accomplir cela en ajoutant l'octroi à la vue et en ne faisant rien de toute façon sur les tables.

Voici un exemple rapide où SELECTn'a pas été explicitement accordé sur la table, mais l'a été dans la vue. L'utilisateur peut sélectionner dans la vue mais pas dans la table.

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;

Notez que cela suppose fooqu'aucun privilège élevé ne lui a été accordé via des autorisations explicites sur le schéma ou la base de données, ou via l'appartenance à un rôle ou à un groupe.

Étant donné que vous utilisez des tables dans plusieurs bases de données (désolé d'avoir manqué la fin de cette première phrase au départ), vous pouvez également avoir besoin d'autorisations explicites sur les tables de la base de données où la vue n'existe pas. Afin d'éviter d'accorder une sélection aux tables, vous pouvez créer une vue dans chaque base de données, puis joindre les vues.

Créez deux bases de données et un identifiant:

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

Dans la base de données d1, créez un utilisateur, puis créez une table et une vue simple sur cette table. Accordez une sélection à l'utilisateur uniquement par rapport à la vue:

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

Maintenant, dans la deuxième base de données, créez l'utilisateur, puis créez une autre table et une vue qui joint cette table à la vue dans d1. Accordez la sélection uniquement à la vue.

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

Lancez maintenant une nouvelle fenêtre de requête et modifiez les informations d'identification pour la connexion blat( EXECUTE ASne fonctionne pas ici). Exécutez ensuite ce qui suit à partir du contexte de l'une ou l'autre base de données, et cela devrait fonctionner correctement:

SELECT id FROM d1.dbo.v2;

Ceux-ci devraient tous deux générer des erreurs Msg 229:

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

Résultats:

Msg 229, niveau 14, état 5, ligne 1
L'autorisation SELECT a été refusée sur l'objet 't1', la base de données 'd1', le schéma 'dbo'.
Msg 229, niveau 14, état 5, ligne 3
L'autorisation SELECT a été refusée sur l'objet 't2', la base de données 'd2', le schéma 'dbo'.

Aaron Bertrand
la source
1

Réponse wiki communautaire ajoutée à l'origine à la question par son auteur:

C'est ce que j'ai fait:

  1. Création d'une vue dans la base de données A, joignant toutes les tables qu'elle contient.
  2. Accordé l' SELECTaccès à l'utilisateur sur cette vue et NON à aucune de ses tables. L'utilisateur a réussi à interroger la vue et non les tables.
  3. Création d'une vue dans la base de données B, joignant les tables de cette base de données avec la vue dans la base de données A.
  4. Accordé un SELECTaccès à l'utilisateur sur cette deuxième vue, et également à aucune table. L'utilisateur a réussi à interroger cette vue finale et à voir les données.

Je pense qu'il est étrange qu'une vue soit capable d'interroger des tables dans sa base de données que l'utilisateur n'a pas d'accès direct mais ne puisse pas le faire dans les tables d'autres bases de données. Au moins ça a marché.

user126897
la source