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 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 à SELECT
nouveau 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_db
pour 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.