Comment ajouter un utilisateur ayant accès à une seule vue?

14

Je travaille avec MSSQL Server Management Studio 2008 et j'ai besoin d'exposer une vue à un tiers pour leur réconciliation des données. J'ai créé la vue appropriée, mais j'ai du mal à créer un utilisateur et à lui accorder les autorisations appropriées pour effectuer une sélection dans la vue.

J'ai suivi les assistants pour créer une connexion et un utilisateur, puis j'ai ajouté ma vue dans la section Securables avec la case d'autorisation cochée pour sélectionner. Tout semblait bien mais quand je me suis connecté en tant qu'utilisateur et que j'ai essayé de faire un "Select * from MyViewName", il m'a dit que l'autorisation de sélection avait été refusée.

Je viens de recréer l'utilisateur (cette fois en utilisant simplement SQL au lieu de l'assistant) et 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.j'ai explicitement accordé des autorisations de sélection et maintenant cela me donne l'erreur: (je ne sais pas pourquoi il essaie d'accéder à la base de données non liée ...)

Je ne sais vraiment pas où aller d'ici. Encore une fois, tout ce dont j'ai besoin est de créer un utilisateur que je peux donner au tiers pour qu'il se connecte à notre base de données et sélectionne dans cette vue.

velojason
la source
3
La vue fait-elle référence aux tables de base dans d'autres bases de données? Si c'est le cas, vous devrez gérer le chaînage de la propriété. Assurez-vous également que le contexte de base de données est actuellement défini sur la base de données souhaitée.
Thomas Stringer
Existe-t-il un moyen de voir les dépendances d'une vue? Je veux dire, pour autant que je sache, tout de la vue devrait être contenu dans la base de données principale. La vue n'est constituée que de trois champs, deux provenant d'une table de détails de paiement et un provenant d'une jointure à la table de détails de compte, mais les deux tables se trouvent dans la même base de données (et la même base de données que la vue).
velojason

Réponses:

16

Veuillez ne pas utiliser l'interface utilisateur pour cela. C'est un désordre déroutant.

Il me semble que ce que vous voulez, c'est créer un utilisateur dans une base de données, pour une connexion spécifique, qui n'a que les autorisations pour sélectionner dans une vue. Donc, puisque vous avez déjà créé la connexion:

USE your_db;
GO
CREATE USER username FROM LOGIN username;
GO
GRANT SELECT ON dbo.MyViewName TO username;
GO

MODIFIER ici est un exemple de script qui conduira à l'erreur que vous mentionnez.

Tout d'abord, créez une table dans le unrelated_db:

CREATE DATABASE unrelated_db;
GO
USE unrelated_db;
GO
CREATE TABLE dbo.foo(bar INT);
GO

Créez maintenant une connexion relativement restreinte:

USE [master];
GO
CREATE LOGIN username WITH PASSWORD='foo', CHECK_POLICY = OFF;
GO

Créez maintenant une base de données où la vue va vivre et ajoutez la connexion en tant qu'utilisateur:

CREATE DATABASE velojason;
GO
USE velojason;
GO
CREATE USER username FROM LOGIN username;
GO

Créez maintenant une fonction qui référencera la table dans l'autre base de données et un synonyme de l'autre table:

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

Créez maintenant une table locale:

CREATE TABLE dbo.PaymentDetails
(
  PaymentID INT
);
GO

Créez maintenant une vue qui référence la table, la fonction et le synonyme, et accordez 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

Essayez maintenant d'exécuter en tant que usernameet sélectionnez uniquement la colonne locale dans la vue:

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

Résultat:

Msg 916, niveau 14, état 1, ligne 3
Le principal du serveur "nom d'utilisateur" n'est pas en mesure d'accéder à la base de données "unrelated_db" dans le contexte de sécurité actuel.

Maintenant, changez la vue pour ne référencer aucun objet externe et exécutez à SELECTnouveau ce qui précède , et cela fonctionne:

ALTER VIEW dbo.SomeView
AS
  SELECT 
    p.PaymentID 
    --x = dbo.checkbar(),
    --y = (SELECT bar FROM dbo.foo)
    FROM dbo.PaymentDetails AS p;
GO

À moins de nous montrer les scripts des objets Détails du paiement, Détails du compte et MyView, vous pouvez peut-être nous faire savoir si cette requête renvoie des résultats. Vous pouvez trouver des références à divers objets via la vue du catalogue sys.sql_expression_dependencies, mais cette vue n'est pas parfaite - je crois qu'elle dépend de toutes les vues actualisées (dans le cas où les vues font référence à d'autres vues, par exemple, ou le schéma sous-jacent a changé) afin pour être précis.

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 ne va pas simplement essayer d'accéder unrelated_dbpour le plaisir ... il doit y avoir un lien avec cette base de données à partir de la vue que vous essayez d'utiliser. Malheureusement, si nous ne pouvons pas voir la définition de la vue et plus de détails sur les objets qu'elle touche, tout ce que nous pouvons faire est de spéculer. Les deux principales choses auxquelles je peux penser sont des synonymes ou des fonctions qui utilisent des noms en trois parties, mais voir les scripts réels nous donnera une bien meilleure idée au lieu de deviner. :-)

Vous pouvez également vérifier sys.dm_sql_referenced_entities, mais cette fonction ne renvoie rien d'utile dans l'exemple ci-dessus.

Aaron Bertrand
la source
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

Vous pouvez tester cela en procédant comme suit:

execute as user = 'YourTpvUser'
go

select *
from YourView

revert
go
Thomas Stringer
la source
Apparemment, cela n'accorde pas récursivement des privilèges. L'utilisateur est autorisé à sélectionner dans "YourView" mais si "YourView" dépend d'autres relations / bases de données, il échouera: Le serveur principal "YourTpvUser" n'est pas en mesure d'accéder à la base de données "OtherDb" dans le contexte de sécurité actuel.
lilalinux