Como adicionar um usuário com acesso a uma única exibição?

14

Estou trabalhando com o MSSQL Server Management Studio 2008 e preciso expor uma visualização a terceiros para a reconciliação de dados. Eu criei a exibição apropriada, mas estou tendo problemas para criar um usuário e conceder a ele as permissões apropriadas para selecionar na exibição.

Segui os assistentes para criar um login e um usuário e, em seguida, adicionei minha exibição na seção Segurables com a caixa de concessão marcada para selecionar. Tudo parecia bem, mas quando eu entrei como usuário e tentei fazer um "Select * from MyViewName", ele me disse que a permissão de seleção foi negada.

Acabei de recriar o usuário (desta vez usando SQL em vez do assistente) e concedeu explicitamente permissões de seleção e agora está me dando o erro: 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.(não sei por que ele está tentando acessar o banco de dados não relacionado ...)

Eu realmente não sei para onde ir daqui. Novamente, basicamente tudo o que preciso é criar um usuário que eu possa dar a terceiros para que eles se conectem ao nosso banco de dados e selecione nessa visualização.

velojason
fonte
3
A exibição faz referência a tabelas base em outros bancos de dados? Nesse caso, você terá que lidar com o encadeamento de propriedade. Além disso, verifique se o contexto do banco de dados está definido no banco de dados desejado.
Thomas Stringer
Existe alguma maneira de ver as dependências para uma exibição? Quero dizer, tanto quanto sei, tudo do ponto de vista deve estar contido no banco de dados principal. A visualização é apenas três campos, dois provenientes de uma tabela de detalhes de pagamento e um proveniente de uma associação à tabela de detalhes da conta, mas ambas estão no mesmo banco de dados (e no mesmo banco de dados da visualização).
precisa saber é o seguinte

Respostas:

16

Por favor, não use a interface do usuário para isso. É uma bagunça confusa.

Parece-me que o que você deseja é criar um usuário em um banco de dados, para um login específico, que tenha apenas permissões para selecionar em uma exibição. Então, já que você já criou o login:

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

EDIT aqui é um exemplo de script que levará ao erro que você mencionou.

Primeiro, crie alguma tabela no unrelated_db:

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

Agora crie um login relativamente restrito:

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

Agora crie um banco de dados no qual a visualização permanecerá e adicione o logon como usuário:

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

Agora crie uma função que fará referência à tabela no outro banco de dados e um sinônimo para a outra tabela:

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

Agora crie uma tabela local:

CREATE TABLE dbo.PaymentDetails
(
  PaymentID INT
);
GO

Agora crie uma visualização que faça referência à tabela, à função e ao sinônimo e conceda SELECTa 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

Agora tente executar como usernamee selecione apenas a coluna local na exibição:

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

Resultado:

Mensagem 916, Nível 14, Estado 1, Linha 3
O principal "nome de usuário" do servidor não pode acessar o banco de dados "unrelated_db" no contexto de segurança atual.

Agora altere a exibição para não fazer referência a objetos externos e execute o acima SELECTnovamente, e ele funciona:

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

Com exceção de nos mostrar os scripts para os objetos Detalhes do pagamento, Detalhes da conta e MyView, talvez você possa nos informar se essa consulta retorna algum resultado. Você pode encontrar referências a vários objetos através da visualização de catálogo sys.sql_expression_dependencies, mas essa visualização não é perfeita - acredito que depende de todas as visualizações serem atualizadas (no caso em que visualizações referenciam outras visualizações, por exemplo, ou o esquema subjacente foi alterado) em ordem Para ser exato.

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;

O SQL Server não está apenas tentando acessar unrelated_db por diversão ... deve haver algum vínculo com esse banco de dados da exibição que você está tentando usar. Infelizmente, se não conseguimos ver a definição da visualização e mais detalhes sobre os objetos em que ela toca, tudo o que podemos fazer é especular. As duas principais coisas em que consigo pensar são sinônimos ou funções que usam nomes de três partes, mas ver os scripts reais nos dará uma idéia muito melhor do que adivinhar. :-)

Você também pode querer verificar sys.dm_sql_referenced_entities, no entanto, esta função não retorna nada útil no exemplo acima.

Aaron Bertrand
fonte
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

Você pode testar isso fazendo o seguinte:

execute as user = 'YourTpvUser'
go

select *
from YourView

revert
go
Thomas Stringer
fonte
Aparentemente, isso não concede privilégios recursivamente. O usuário pode selecionar entre "YourView", mas se "YourView" depender de outras relações / bancos de dados, ocorrerá um erro: O servidor principal "YourTpvUser" não poderá acessar o banco de dados "OtherDb" no contexto de segurança atual.
lilalinux