web-dev-qa-db-fra.com

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

Je travaille avec MSSQL Server Management Studio 2008 et je dois exposer une vue à un tiers pour leur rapprochement 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 lorsque 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 j'ai explicitement accordé des autorisations de sélection et maintenant il me donne l'erreur: 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. (Je ne sais pas pourquoi il essaie d'accéder à la base de données indépendante ...)

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.

14
velojason

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 [~ # ~] voici 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 username et 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 à nouveau le SELECT ci-dessus, 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 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 d'ê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_db pour le plaisir ... il doit y avoir un lien avec cette base de données depuis 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.

16
Aaron Bertrand
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
6
Thomas Stringer