Model keamanan SQL Server memungkinkan Anda untuk memberikan akses ke tampilan tanpa memberikan akses ke tabel yang mendasarinya.
Karena kode contoh adalah cara yang bagus untuk menunjukkan konsep, pertimbangkan yang berikut, dengan LoginDetails
tabel, dan tampilan yang sesuai:
CREATE TABLE dbo.LoginDetails
(
Username nvarchar(100) NOT NULL
, EmailAddress nvarchar(256) NOT NULL
, LastLoggedInAt datetime NULL
);
GO
CREATE VIEW dbo.LoginDetailsView
AS
SELECT ld.Username
, ld.EmailAddress
, ld.LastLoggedInAt
FROM dbo.LoginDetails ld
WHERE ld.LastLoggedInAt IS NOT NULL;
GO
Kami akan membuat login, dan pengguna, lalu memberikan hak kepada pengguna itu untuk memilih baris dari tampilan, tanpa memiliki hak untuk melihat tabel itu sendiri.
CREATE LOGIN RemoteUser
WITH PASSWORD = '2q1345lkjsadfgsa0(*';
CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;
GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;
Sekarang, kami akan memasukkan dua baris uji:
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
Ini menguji model keamanan. SELECT
Pernyataan pertama berhasil, karena memilih dari tampilan, sedangkan SELECT
pernyataan kedua gagal karena pengguna tidak memiliki akses langsung ke tabel.
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetailsView;
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Nama Pengguna ║ Alamat Email ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ pengguna y ║ y@y.com ║ 2018-02-15 07: 36: 54.490 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
SELECT *
FROM dbo.LoginDetails;
REVERT
Catat hasil dari tampilan mengecualikan baris tempat LastLoggedInAt
nilainya NULL
, seperti yang dipersyaratkan dalam pertanyaan Anda.
SELECT
Pernyataan kedua terhadap tabel yang mendasari menghasilkan kesalahan:
Msg 229, Level 14, Negara 5, Jalur 28
Izin SELECT ditolak pada objek 'LoginDetails', database 'tempdb', schema 'dbo'.
Membersihkan:
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP VIEW dbo.LoginDetailsView;
DROP TABLE dbo.LoginDetails;
Sebagai alternatif, jika Anda memiliki SQL Server 2016 atau yang lebih baru, Anda bisa menggunakan predikat tingkat-keamanan untuk mencegah pengguna tertentu melihat baris dengan LastLoggedInAt
nilai NULL .
Pertama, kami membuat tabel, login, pengguna untuk login itu, dan kami memberikan akses ke tabel:
CREATE TABLE dbo.LoginDetails
(
Username nvarchar(100) NOT NULL
, EmailAddress nvarchar(256) NOT NULL
, LastLoggedInAt datetime NULL
);
GO
CREATE LOGIN RemoteUser
WITH PASSWORD = '2q1345lkjsadfgsa0(*';
CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;
GRANT SELECT ON dbo.LoginDetails TO RemoteUser;
Selanjutnya, kami menyisipkan beberapa baris sampel. Satu baris dengan nol LastLoggedInAt
, dan satu dengan nilai bukan nol untuk kolom itu.
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
Di sini, kami membuat fungsi tabel-nilai-terikat-skema-terikat yang mengembalikan baris dengan 0 atau 1 tergantung pada nilai @LastLoggedInAt
dan @username
variabel yang diteruskan ke fungsi. Fungsi ini akan digunakan oleh predikat-filter untuk menghilangkan baris yang ingin kita sembunyikan dari pengguna tertentu.
CREATE FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate
(
@LastLoggedInAt datetime
, @username sysname
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS fn_securitypredicate_result
WHERE (@username = N'RemoteUser' AND @LastLoggedInAt IS NOT NULL)
OR @username <> N'RemoteUser';
GO
Ini adalah filter keamanan yang menghilangkan baris dari SELECT
pernyataan yang dijalankan terhadap dbo.LoginDetails
tabel:
CREATE SECURITY POLICY LoginDetailsRemoteUserPolicy
ADD FILTER PREDICATE dbo.fn_LoginDetailsRemoteUserPredicate(LastLoggedInAt, USER_NAME())
ON dbo.LoginDetails
WITH (STATE=ON);
Filter di atas menggunakan dbo.fn_LoginDetailsRemoteUserPredicate
fungsi dengan mengirimkan nama pengguna saat ini, bersama dengan nilai dari setiap baris untuk LastLoggedInAt
kolom dari dbo.LoginDetails
tabel.
Jika kami meminta tabel sebagai pengguna normal:
SELECT *
FROM dbo.LoginDetails
kita melihat semua baris:
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Nama Pengguna ║ Alamat Email ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ pengguna x ║ x@y.com ║ NULL ║
║ pengguna y ║ y@y.com ║ 2018-02-15 13: 53: 42.577 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
Namun, jika kami uji sebagai RemoteUser
:
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetails
REVERT
kami hanya melihat baris "valid":
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Nama Pengguna ║ Alamat Email ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ pengguna y ║ y@y.com ║ 2018-02-15 13: 42: 02.023 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
Dan, kami membersihkan:
DROP SECURITY POLICY LoginDetailsRemoteUserPolicy;
DROP FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate;
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP TABLE dbo.LoginDetails;
Perlu diketahui bahwa pengikatan skema fungsi ke tabel dengan cara ini tidak membuat tidak mungkin untuk mengubah definisi tabel tanpa terlebih dahulu menjatuhkan predikat filter, dan dbo.fn_LoginDetailsRemoteUserPredicate
fungsi.