web-dev-qa-db-ja.com

単一のビューへのアクセス権を持つユーザーを追加するにはどうすればよいですか?

MSSQL Server Management Studio 2008を使用していて、データ調整のためにビューをサードパーティに公開する必要があります。適切なビューを作成しましたが、ユーザーを作成できず、ビューから選択するための適切な権限をそのユーザーに与えることができません。

ウィザードに従ってログインとユーザーを作成し、ビューを[セキュリティ保護可能なセクション]に追加して、選択のために許可ボックスをオンにしました。すべてが問題ないように見えましたが、そのユーザーとしてログインして「Select * from 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.(無関係のデータベースにアクセスしようとしている理由がわかりません...)

ここからどこへ行くのか本当に分かりません。繰り返しますが、基本的に必要なのは、サードパーティにデータベースを接続してこのビューから選択してもらうためにサードパーティに提供できるユーザーを作成することだけです。

14
velojason

これにはUIを使用しないでください。それは混乱を招く混乱です。

1つのビューから選択する権限しか持たない特定のログインに対して、データベースにユーザーを作成するのが好きなように思えます。したがって、すでにログインが作成されているので、

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

[〜#〜] edit [〜#〜]これは、あなたが言及したエラーにつながるスクリプトの例です。

まず、unrelated_dbにテーブルを作成します。

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

次に、比較的制限されたログインを作成します。

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

次に、ビューを配置するデータベースを作成し、ユーザーとしてログインを追加します。

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

次に、他のデータベースのテーブルを参照する関数と、他のテーブルのシノニムを作成します。

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

次に、ローカルテーブルを作成します。

CREATE TABLE dbo.PaymentDetails
(
  PaymentID INT
);
GO

次に、テーブル、関数、シノニムを参照するビューを作成し、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

次に、usernameとして実行して、ビューからローカル列のみを選択します。

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

結果:

メッセージ916、レベル14、状態1、行3
サーバープリンシパル「username」は、現在のセキュリティコンテキストではデータベース「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

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;

SQL Serverはunrelated_dbにアクセスしようとするだけではありません...使用しようとしているビューからそのデータベースに何らかの結びつきがあるはずです。残念ながら、ビューの定義と、それに関係するオブジェクトの詳細が表示されない場合は、推測することしかできません。私が考えることができる2つの主なことは、3部構成の名前を使用する同義語または関数ですが、実際のスクリプトを見ると、推測するよりもはるかに優れたアイデアが得られます。 :-)

sys.dm_sql_referenced_entities を確認することもできますが、この関数は上記の例では何も返しません。

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

これをテストするには、次のようにします。

execute as user = 'YourTpvUser'
go

select *
from YourView

revert
go
6
Thomas Stringer