Bagaimana cara menambahkan pengguna dengan akses ke satu tampilan?

14

Saya bekerja dengan MSSQL Server Management Studio 2008 dan saya perlu mengekspos pandangan kepada pihak ketiga untuk rekonsiliasi data mereka. Saya telah membuat tampilan yang sesuai, tetapi saya mengalami masalah dalam membuat pengguna dan memberikan izin yang sesuai kepada pengguna untuk memilih dari tampilan.

Saya mengikuti panduan untuk membuat login dan pengguna dan kemudian menambahkan pandangan saya di bagian Securables dengan kotak hibah dicentang untuk pilih. Semuanya tampak baik-baik saja tetapi ketika saya login sebagai pengguna itu dan mencoba melakukan "Pilih * dari MyViewName" itu memberi tahu saya bahwa izin pilih ditolak.

Saya baru saja membuat ulang pengguna (kali ini hanya menggunakan SQL, bukan wizard) dan secara eksplisit diberikan izin pilih dan sekarang itu memberi saya kesalahan: 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. (Saya tidak tahu mengapa ia mencoba mengakses database yang tidak terkait ...)

Saya benar-benar tidak tahu harus ke mana dari sini. Sekali lagi, pada dasarnya yang saya butuhkan adalah membuat pengguna yang dapat saya berikan kepada pihak ketiga agar mereka terhubung ke database kami dan memilih dari tampilan ini.

velojason
sumber
3
Apakah tabel referensi referensi tampilan di database lain? Jika demikian, Anda harus berurusan dengan rantai kepemilikan. Juga, pastikan bahwa Anda saat ini mengatur konteks database ke database yang diinginkan.
Thomas Stringer
Apakah ada cara untuk melihat dependensi untuk tampilan? Maksud saya, sejauh yang saya tahu, segala sesuatu dari tampilan harus terkandung dalam database utama. Tampilannya hanya tiga bidang, dua berasal dari tabel detail pembayaran dan satu berasal dari gabungan ke tabel detail akun tetapi kedua tabel berada di database yang sama (dan database yang sama dengan tampilan).
velojason

Jawaban:

16

Tolong jangan gunakan UI untuk ini. Ini kekacauan yang membingungkan.

Bagi saya itu seperti apa yang Anda inginkan adalah membuat pengguna dalam database, untuk login tertentu, yang hanya memiliki izin untuk memilih dari satu tampilan. Jadi, karena Anda sudah membuat login:

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

EDIT di sini adalah contoh skrip yang akan menyebabkan kesalahan yang Anda sebutkan.

Pertama, buat beberapa tabel di unrelated_db:

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

Sekarang buat login yang relatif terbatas:

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

Sekarang buat basis data tempat tampilan akan hidup, dan tambahkan login sebagai pengguna:

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

Sekarang buat fungsi yang akan mereferensikan tabel di database lain, dan sinonim dengan tabel lainnya:

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

Sekarang buat tabel lokal:

CREATE TABLE dbo.PaymentDetails
(
  PaymentID INT
);
GO

Sekarang buat tampilan yang mereferensikan tabel, fungsi dan sinonim, dan berikan SELECTkepada 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

Sekarang coba jalankan sebagai usernamedan pilih hanya kolom lokal dari tampilan:

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

Hasil:

Msg 916, Level 14, State 1, Line 3
Prinsipal server "username" tidak dapat mengakses database "unrelated_db" di bawah konteks keamanan saat ini.

Sekarang ubah tampilan untuk tidak mereferensikan objek eksternal, dan jalankan SELECTlagi di atas , dan itu berfungsi:

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

Tanpa menunjukkan kepada kami skrip untuk Detail Pembayaran, Detail Akun, dan objek MyView, mungkin Anda dapat memberi tahu kami jika kueri ini mengembalikan hasil apa pun. Anda dapat menemukan referensi ke berbagai objek melalui tampilan katalog sys.sql_expression_dependencies, tetapi tampilan ini tidak sempurna - saya percaya itu tergantung pada semua tampilan yang di-refresh (dalam kasus di mana tampilan referensi tampilan lain, misalnya, atau skema yang mendasarinya telah berubah) agar untuk lebih akurat.

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 tidak hanya akan mencoba mengakses unrelated_db untuk bersenang-senang ... harus ada ikatan dengan database dari tampilan yang Anda coba gunakan. Sayangnya jika kita tidak dapat melihat definisi tampilan dan detail lebih lanjut tentang objek yang disentuhnya, yang bisa kita lakukan hanyalah berspekulasi. Dua hal utama yang dapat saya pikirkan adalah sinonim atau fungsi yang menggunakan nama tiga bagian, tetapi melihat skrip yang sebenarnya akan memberi kita ide yang jauh lebih baik daripada menebak. :-)

Anda mungkin juga ingin memeriksa sys.dm_sql_referenced_entities, namun fungsi ini tidak mengembalikan apa pun yang berguna dalam contoh di atas.

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

Anda dapat menguji ini dengan melakukan hal berikut:

execute as user = 'YourTpvUser'
go

select *
from YourView

revert
go
Thomas Stringer
sumber
Tampaknya ini tidak secara rekursif memberikan hak istimewa. Pengguna diizinkan untuk memilih dari "YourView" tetapi jika "YourView" tergantung pada hubungan / database lain, itu akan gagal: Prinsip server "YourTpvUser" tidak dapat mengakses database "OtherDb" di bawah konteks keamanan saat ini.
lilalinux