Mit dem SQL Server-Sicherheitsmodell können Sie Zugriff auf eine Ansicht gewähren, ohne Zugriff auf die zugrunde liegenden Tabellen zu gewähren.
Da Beispielcode eine hervorragende Möglichkeit ist, ein Konzept LoginDetails
anzuzeigen, sollten Sie Folgendes mit einer Tabelle und der entsprechenden Ansicht berücksichtigen :
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
Wir erstellen ein Login und einen Benutzer und weisen diesem Benutzer dann die Rechte zu, Zeilen aus der Ansicht auszuwählen, ohne über Rechte zum Anzeigen der Tabelle selbst zu verfügen.
CREATE LOGIN RemoteUser
WITH PASSWORD = '2q1345lkjsadfgsa0(*';
CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;
GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;
Jetzt fügen wir zwei Testzeilen ein:
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
Dies testet das Sicherheitsmodell. Die erste SELECT
Anweisung ist erfolgreich, da sie aus der Ansicht ausgewählt wird, während die zweite SELECT
Anweisung fehlschlägt, weil der Benutzer keinen direkten Zugriff auf die Tabelle hat.
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetailsView;
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Benutzername ║ EmailAddress ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ Benutzer y ║ y@y.com ║ 15.02.2018 07: 36: 54.490 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
SELECT *
FROM dbo.LoginDetails;
REVERT
Beachten Sie, dass die Ergebnisse aus der Ansicht die Zeile ausschließen, in der sich der LastLoggedInAt
Wert befindet NULL
, wie in Ihrer Frage erforderlich.
Die zweite SELECT
Anweisung für die zugrunde liegende Tabelle gibt einen Fehler zurück:
Nachricht 229, Ebene 14,
Status 5, Zeile 28 Die SELECT-Berechtigung wurde für das Objekt 'LoginDetails', Datenbank 'tempdb', Schema 'dbo' verweigert.
Aufräumen:
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP VIEW dbo.LoginDetailsView;
DROP TABLE dbo.LoginDetails;
Wenn Sie über SQL Server 2016 oder höher verfügen, können Sie alternativ ein Sicherheitsprädikat auf Zeilenebene verwenden, um zu verhindern, dass bestimmte Benutzer Zeilen mit einem NULL- LastLoggedInAt
Wert sehen.
Zuerst erstellen wir die Tabelle, ein Login, einen Benutzer für dieses Login und gewähren Zugriff auf die Tabelle:
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;
Als nächstes fügen wir einige Beispielzeilen ein. Eine Zeile mit einer Null LastLoggedInAt
und eine mit einem Wert ungleich Null für diese Spalte.
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
Hier erstellen wir eine schemagebundene Tabellenwertfunktion, die abhängig vom Wert der @LastLoggedInAt
und der @username
Variablen, die an die Funktion übergeben werden , eine Zeile mit 0 oder 1 zurückgibt . Diese Funktion wird von einem Filterprädikat verwendet, um die Zeilen zu entfernen, die wir vor bestimmten Benutzern verbergen möchten.
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
Dies ist der Sicherheitsfilter, der Zeilen aus SELECT
Anweisungen entfernt, die für die dbo.LoginDetails
Tabelle ausgeführt werden:
CREATE SECURITY POLICY LoginDetailsRemoteUserPolicy
ADD FILTER PREDICATE dbo.fn_LoginDetailsRemoteUserPredicate(LastLoggedInAt, USER_NAME())
ON dbo.LoginDetails
WITH (STATE=ON);
Der obige Filter verwendet die dbo.fn_LoginDetailsRemoteUserPredicate
Funktion, indem er den Namen des aktuellen Benutzers zusammen mit den Werten aus jeder Zeile für die LastLoggedInAt
Spalte aus der dbo.LoginDetails
Tabelle übergibt .
Wenn wir die Tabelle als normaler Benutzer abfragen:
SELECT *
FROM dbo.LoginDetails
wir sehen alle Zeilen:
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Benutzername ║ EmailAddress ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ Benutzer x ║ x@y.com ║ NULL ║
║ Benutzer y ║ y@y.com ║ 2018-02-15 13: 53: 42.577 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
Wenn wir jedoch Folgendes testen RemoteUser
:
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetails
REVERT
Wir sehen nur "gültige" Zeilen:
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Benutzername ║ EmailAddress ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ Benutzer y ║ y@y.com ║ 15.02.2018 13: 42: 02.023 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
Und wir räumen auf:
DROP SECURITY POLICY LoginDetailsRemoteUserPolicy;
DROP FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate;
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP TABLE dbo.LoginDetails;
Beachten Sie, dass das Schema, das eine Funktion auf diese Weise an die Tabelle bindet, es unmöglich macht, die Definition der Tabelle zu ändern, ohne zuerst das Filterprädikat und die dbo.fn_LoginDetailsRemoteUserPredicate
Funktion zu löschen.