如何添加有权访问单个视图的用户?

vel*_*son 14 sql-server-2008 sql-server view remote

我正在使用 MSSQL Server Management Studio 2008,我需要向第三方公开一个视图以进行数据协调。我已经创建了适当的视图,但是我在创建用户并授予该用户从视图中进行选择的适当权限时遇到了问题。

我按照向导创建了一个登录名和一个用户,然后在 Securables 部分添加了我的视图,并选中了选中的授权框。一切似乎都很好,但是当我以该用户身份登录并尝试执行“从 MyViewName 中选择 *”时,它告诉我选择权限被拒绝。

我刚刚重新创建了用户(这次只是使用 SQL 而不是向导)并明确授予了选择权限,现在它给了我错误:(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.我不知道为什么它试图访问不相关的数据库......)

我真的不知道从这里去哪里。同样,基本上我所需要的只是创建一个用户,我可以将其提供给第三方,让他们连接到我们的数据库并从此视图中进行选择。

Aar*_*and 17

请不要为此使用 UI。这是一个混乱的混乱。

在我看来,您想要的是在数据库中为特定登录创建一个用户,该用户只能从一个视图中进行选择。因此,由于您已经创建了登录名:

USE your_db;
GO
CREATE USER username FROM LOGIN username;
GO
GRANT SELECT ON dbo.MyViewName TO username;
GO
Run Code Online (Sandbox Code Playgroud)

编辑这里是一个脚本示例,它会导致您提到的错误。

首先,在 unrelated_db 中创建一些表:

CREATE DATABASE unrelated_db;
GO
USE unrelated_db;
GO
CREATE TABLE dbo.foo(bar INT);
GO
Run Code Online (Sandbox Code Playgroud)

现在创建一个相对受限的登录:

USE [master];
GO
CREATE LOGIN username WITH PASSWORD='foo', CHECK_POLICY = OFF;
GO
Run Code Online (Sandbox Code Playgroud)

现在创建一个视图所在的数据库,并将登录添加为用户:

CREATE DATABASE velojason;
GO
USE velojason;
GO
CREATE USER username FROM LOGIN username;
GO
Run Code Online (Sandbox Code Playgroud)

现在创建一个将引用另一个数据库中的表的函数,以及另一个表的同义词:

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
Run Code Online (Sandbox Code Playgroud)

现在创建一个本地表:

CREATE TABLE dbo.PaymentDetails
(
  PaymentID INT
);
GO
Run Code Online (Sandbox Code Playgroud)

现在创建一个观点,即引用表,函数和同义词,并授予SELECTusername

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
Run Code Online (Sandbox Code Playgroud)

现在尝试执行 asusername并从视图中仅选择本地列:

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
Run Code Online (Sandbox Code Playgroud)

结果:

消息 916,级别 14,状态 1,第 3 行
服务器主体“用户名”无法访问当前安全上下文下的数据库“unrelated_db”。

现在将视图更改为不引用任何外部对象,然后SELECT再次运行上面的代码,它可以工作:

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

除了向我们展示 Payment Details、Account Details 和 MyView 对象的脚本之外,也许您可​​以让我们知道此查询是否返回任何结果。您可以通过目录视图找到对各种对象的引用sys.sql_expression_dependencies,但是这个视图并不完美——我相信这取决于所有被刷新的视图(例如,在视图引用其他视图的情况下,或者基础架构已经改变的情况下)要准确。

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;
Run Code Online (Sandbox Code Playgroud)

SQL Server 不会仅仅为了unrelated_db它的乐趣而尝试访问……从您尝试使用的视图来看,必须与该数据库有某种联系。不幸的是,如果我们看不到视图定义和它所接触对象的更多细节,我们所能做的就是推测。我能想到的两个主要事情是使用三部分名称的同义词或函数,但查看实际脚本会给我们一个更好的主意,而不是猜测。:-)

您可能还想检查sys.dm_sql_referenced_entities,但是这个函数在上面的例子中没有返回任何有用的东西。


Tho*_*ger 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
Run Code Online (Sandbox Code Playgroud)

您可以通过执行以下操作来测试:

execute as user = 'YourTpvUser'
go

select *
from YourView

revert
go
Run Code Online (Sandbox Code Playgroud)