Mô hình bảo mật SQL Server cho phép bạn cấp quyền truy cập vào chế độ xem mà không cấp quyền truy cập vào các bảng bên dưới.
Vì mã ví dụ là một cách tuyệt vời để hiển thị một khái niệm, hãy xem xét các điều sau đây, với một LoginDetails
bảng và chế độ xem tương ứng:
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
Chúng tôi sẽ tạo thông tin đăng nhập và người dùng, sau đó gán cho người dùng quyền đó để chọn các hàng từ chế độ xem mà không có bất kỳ quyền nào để xem chính bảng đó.
CREATE LOGIN RemoteUser
WITH PASSWORD = '2q1345lkjsadfgsa0(*';
CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;
GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;
Bây giờ, chúng tôi sẽ chèn hai hàng thử nghiệm:
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
Điều này kiểm tra mô hình bảo mật. Câu SELECT
lệnh đầu tiên thành công, vì nó đang chọn từ khung nhìn, trong khi SELECT
câu lệnh thứ hai không thành công vì người dùng không có quyền truy cập trực tiếp vào bảng.
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetailsView;
╔══════════╦══════════════╦═══════════════════════ ══╗
Tên người dùng EmailAddress LastLoggedInAt
╠══════════╬══════════════╬═══════════════════════ ══╣
Người dùng y ║ y@y.com 2018-02-15 07: 36: 54.490
╚══════════╩══════════════╩═══════════════════════ ══╝
SELECT *
FROM dbo.LoginDetails;
REVERT
Lưu ý các kết quả từ chế độ xem loại trừ hàng có LastLoggedInAt
giá trị NULL
, như được yêu cầu trong câu hỏi của bạn.
Câu SELECT
lệnh thứ hai đối với bảng bên dưới trả về lỗi:
Msg 229, Cấp 14, Trạng thái 5, Dòng 28
Quyền CHỌN đã bị từ chối trên đối tượng 'LoginDetails', cơ sở dữ liệu 'tempdb', lược đồ 'dbo'.
Dọn dẹp:
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP VIEW dbo.LoginDetailsView;
DROP TABLE dbo.LoginDetails;
Cách khác, nếu bạn có SQL Server 2016 hoặc mới hơn, bạn có thể sử dụng một vị từ bảo mật cấp hàng để ngăn người dùng nhất định nhìn thấy các hàng có LastLoggedInAt
giá trị NULL .
Đầu tiên, chúng tôi tạo bảng, đăng nhập, người dùng cho thông tin đăng nhập đó và chúng tôi cấp quyền truy cập vào bảng:
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;
Tiếp theo, chúng tôi chèn một vài hàng mẫu. Một hàng có giá trị null LastLoggedInAt
và một hàng có giá trị khác null cho cột đó.
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
Ở đây, chúng ta đang tạo một hàm có giá trị bảng ràng buộc lược đồ trả về một hàng có 0 hoặc 1 tùy thuộc vào giá trị của các biến @LastLoggedInAt
và @username
các biến được truyền vào hàm. Hàm này sẽ được sử dụng bởi một vị từ bộ lọc để loại bỏ các hàng chúng ta muốn ẩn khỏi một số người dùng nhất định.
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
Đây là bộ lọc bảo mật giúp loại bỏ các hàng khỏi các SELECT
câu lệnh chạy trên dbo.LoginDetails
bảng:
CREATE SECURITY POLICY LoginDetailsRemoteUserPolicy
ADD FILTER PREDICATE dbo.fn_LoginDetailsRemoteUserPredicate(LastLoggedInAt, USER_NAME())
ON dbo.LoginDetails
WITH (STATE=ON);
Bộ lọc ở trên sử dụng dbo.fn_LoginDetailsRemoteUserPredicate
hàm bằng cách chuyển tên của người dùng hiện tại, cùng với các giá trị từ mỗi hàng cho LastLoggedInAt
cột từ dbo.LoginDetails
bảng.
Nếu chúng ta truy vấn bảng như một người dùng bình thường:
SELECT *
FROM dbo.LoginDetails
chúng tôi thấy tất cả các hàng:
╔══════════╦══════════════╦═══════════════════════ ══╗
Tên người dùng EmailAddress LastLoggedInAt
╠══════════╬══════════════╬═══════════════════════ ══╣
║ người dùng x ║ x@y.com NULL
Người dùng y ║ y@y.com 2018-02-15 13: 53: 42.577
╚══════════╩══════════════╩═══════════════════════ ══╝
Tuy nhiên, nếu chúng tôi kiểm tra như RemoteUser
:
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetails
REVERT
chúng tôi chỉ thấy các hàng "hợp lệ":
╔══════════╦══════════════╦═══════════════════════ ══╗
Tên người dùng EmailAddress LastLoggedInAt
╠══════════╬══════════════╬═══════════════════════ ══╣
Người dùng y ║ y@y.com 2018-02-15 13: 42: 02.023
╚══════════╩══════════════╩═══════════════════════ ══╝
Và, chúng tôi dọn dẹp:
DROP SECURITY POLICY LoginDetailsRemoteUserPolicy;
DROP FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate;
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP TABLE dbo.LoginDetails;
Xin lưu ý rằng lược đồ liên kết một hàm với bảng theo cách này sẽ không thể sửa đổi định nghĩa của bảng mà không bỏ qua biến vị ngữ bộ lọc và dbo.fn_LoginDetailsRemoteUserPredicate
hàm.