SQL Server逐行访问


Answers:


32

SQL Server安全模型允许您授予对视图的访问权限,而无需授予对基础表的访问权限。

由于示例代码是展示概念的好方法,因此请考虑以下内容,并附有LoginDetails表格和相应的视图:

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

我们将创建一个登录名和一个用户,然后为该用户分配从视图中选择行的权限,而没有查看表本身的任何权限。

CREATE LOGIN RemoteUser 
WITH PASSWORD = '2q1345lkjsadfgsa0(*';

CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;

GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;

现在,我们将插入两个测试行:

INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
    , ('user y', 'y@y.com', GETDATE());

这将测试安全模型。第一条SELECT语句成功,因为它正在从视图中进行选择,而第二条SELECT语句失败,因为用户没有直接访问表的权限。

EXECUTE AS LOGIN = 'RemoteUser';

SELECT *
FROM dbo.LoginDetailsView;
╔══════════╦══════════════╦═══════════════════════ ══╗
║用户名║电子邮件地址║LastLoggedInAt║
╠══════════╬══════════════╬═══════════════════════ ══╣
║用户y║y@y.com║2018-02-15 07:36:54.490║
╚══════════牛皮══════════════牛皮═══════════════════════ ══╝
SELECT *
FROM dbo.LoginDetails;

REVERT

请注意,视图中的结果根据您的问题排除了LastLoggedInAt值为的行NULL

SELECT针对基础表的第二条语句返回错误:

消息229,级别14,状态5,第28行
。对对象“ LoginDetails”,数据库“ tempdb”,模式“ dbo”的SELECT权限被拒绝。

清理:

DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP VIEW dbo.LoginDetailsView;
DROP TABLE dbo.LoginDetails;

或者,如果您具有SQL Server 2016或更高版本,则可以使用行级安全性谓词来防止某些用户看到具有NULL LastLoggedInAt值的行。

首先,我们创建表,登录名,该登录名的用户,然后授予对该表的访问权限:

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;

接下来,我们插入几个示例行。该列的一行为null LastLoggedInAt,另一行的值为非null。

INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
    , ('user y', 'y@y.com', GETDATE());

在这里,我们正在创建一个与模式绑定的表值函数,该函数将根据传递给函数的@LastLoggedInAt@username变量的值返回0或1的行。过滤谓词将使用此函数来消除我们要向某些用户隐藏的行。

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

这是安全过滤器,用于消除SELECT针对dbo.LoginDetails表运行的语句中的行:

CREATE SECURITY POLICY LoginDetailsRemoteUserPolicy
ADD FILTER PREDICATE dbo.fn_LoginDetailsRemoteUserPredicate(LastLoggedInAt, USER_NAME())
ON dbo.LoginDetails
WITH (STATE=ON);

上面的过滤器dbo.fn_LoginDetailsRemoteUserPredicate通过传入当前用户的名称以及表中LastLoggedInAt列的每一行的值来使用该功能dbo.LoginDetails

如果我们以普通用户身份查询表:

SELECT *
FROM dbo.LoginDetails

我们看到所有行:

╔══════════╦══════════════╦═══════════════════════ ══╗
║用户名║电子邮件地址║LastLoggedInAt║
╠══════════╬══════════════╬═══════════════════════ ══╣
║用户x║x@y.com║空║
║用户y║y@y.com║2018-02-15 13:53:42.577║
╚══════════牛皮══════════════牛皮═══════════════════════ ══╝

但是,如果我们测试为RemoteUser

EXECUTE AS LOGIN = 'RemoteUser';

SELECT *
FROM dbo.LoginDetails

REVERT

我们只会看到“有效”行:

╔══════════╦══════════════╦═══════════════════════ ══╗
║用户名║电子邮件地址║LastLoggedInAt║
╠══════════╬══════════════╬═══════════════════════ ══╣
║用户y║y@y.com║2018-02-15 13:42:02.023║
╚══════════牛皮══════════════牛皮═══════════════════════ ══╝

并且,我们清理:

DROP SECURITY POLICY LoginDetailsRemoteUserPolicy;
DROP FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate;
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP TABLE dbo.LoginDetails;

请注意,以这种方式将函数绑定到表确实会导致在不先删除过滤谓词和dbo.fn_LoginDetailsRemoteUserPredicate函数的情况下无法修改表的定义。


出色的答案-谢谢!这两种方法的性能含义是什么?我们发现,使用该功能时,我们的网络应用程序的运行速度最多可降低5倍。需要看一下View方法。
LiamB

对于从表中读取的每一行,都会评估行级安全性功能;我希望它会大大降低对该表的访问速度。另一方面,假设您在该LastLoggedInAt列上创建了有用的索引,则该视图对性能的影响应该忽略不计。
Max Vernon

这是有道理的-我现在来看一下视图,看起来效果不错!如果我们希望用户只能为符合条件的这些行编辑用户数据,那么视图是否可能?
LiamB

它非常漂亮,一切正常-感谢您的帮助
LiamB

是的,您可以通过视图编辑行
Max Vernon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.