Tsql 如何在SQL Server 2016中对明细表实现安全筛选器谓词

Tsql 如何在SQL Server 2016中对明细表实现安全筛选器谓词,tsql,sql-server-2016,Tsql,Sql Server 2016,下面是我们如何在SQL Server 2016中实现安全筛选器谓词的示例。我们在根表上应用了安全规则,并希望将这些规则应用于细节/子表。例如,如果一个销售代表创建了一个由许多装运组成的订单,其中包含许多项目,我们不希望另一个销售代表查询这些项目 USE [TestSecurity2016b] GO /****** Object: Table [dbo].[OrderDetails] Script Date: 2017-01-02 09:14:49 ******/ SET ANSI_NU

下面是我们如何在SQL Server 2016中实现安全筛选器谓词的示例。我们在根表上应用了安全规则,并希望将这些规则应用于细节/子表。例如,如果一个销售代表创建了一个由许多装运组成的订单,其中包含许多项目,我们不希望另一个销售代表查询这些项目

USE [TestSecurity2016b]
GO

/****** Object:  Table [dbo].[OrderDetails]    Script Date: 2017-01-02 09:14:49 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Orders]
(
    [ID] [int] NOT NULL,
    [SalesRep] [sysname] NOT NULL,
) ON [PRIMARY]

CREATE TABLE [dbo].[OrderShipments]
(
    [ID] [int] NOT NULL,
    [FK_OrderID] [int] NOT NULL,
    [TrackingNumber] [varchar](25) NULL,
    [ShippedOn] [Date] NULL,
) ON [PRIMARY]

CREATE TABLE [dbo].[OrderShipmentItems]
(
    [ID] [int] NOT NULL,
    [FK_OrderShipmentID] [int] NOT NULL,
    [Product] [varchar](25) NOT NULL,
    [Quantity] [int] NOT NULL,
) ON [PRIMARY]

GO 

insert dbo.Orders values 
    (1, 'SalesRep1'), 
    (2, 'SalesRep2');

insert dbo.[OrderShipments] values
(1, 1, '1234', '2016-12-25'),
(2, 1, '4321', '2016-12-26'),
(3, 2, '5678', '2017-01-01');

insert dbo.[OrderShipmentItems] values
(1, 1, 'Benq w1070', 1),
(2, 1, '#8 Stainless bolts', 4),
(3, 2, 'HP x360 Laptop', 1),
(4, 3, 'Nintendo NES', 1),
(5, 3, 'Intellivision', 1),
(6, 3, 'Coleco', 1);

GO 

create user Manager without login;
create user SalesRep1 without login;
create user SalesRep2 without login;

GO 

grant select on dbo.Orders to Manager;
grant select on dbo.[OrderShipments] to Manager;
grant select on dbo.[OrderShipmentItems] to Manager;

grant select on dbo.Orders to SalesRep1;
grant select on dbo.[OrderShipments] to SalesRep1;
grant select on dbo.[OrderShipmentItems] to SalesRep1;

grant select on dbo.Orders to SalesRep2;
grant select on dbo.[OrderShipments] to SalesRep2;
grant select on dbo.[OrderShipmentItems] to SalesRep2;

GO 

create function dbo.fn_orderfilter_predicate(@SalesRep as sysname)
    returns table
with schemabinding
as
    return select 1 as result 
where @SalesRep = user_name() or user_name() = 'Manager';

GO 

create function dbo.fn_ordershipmentsfilter_predicate(@FK_OrderID as int)
    returns table
with schemabinding
as
    return select 1 as result 
    where @FK_OrderID in (select ID as OrdersID from dbo.Orders where SalesRep = user_name() or user_name() = 'Manager')

GO

create function dbo.fn_ordershipmentitemsfilter_predicate(@FK_OrderShipmentID as int)
    returns table
with schemabinding
as
    return select 1 as result 
    where @FK_OrderShipmentID in 
    (
        SELECT    OrderShipments.ID AS OrderShipmentID
        FROM    dbo.Orders INNER JOIN
                dbo.OrderShipments ON Orders.ID = OrderShipments.FK_OrderID
        WHERE   (Orders.SalesRep = USER_NAME() OR USER_NAME() = 'Manager') 
                AND (OrderShipments.ID = @FK_OrderShipmentID) 
    )

GO

create security policy OrdersFilter
add filter predicate dbo.fn_orderfilter_predicate(SalesRep) 
on dbo.Orders
with (state = on);

GO

create security policy OrderShipmentsFilter
add filter predicate dbo.fn_ordershipmentsfilter_predicate(FK_OrderID) 
on dbo.OrderShipments
with (state = on);

GO

create security policy OrderShipmentItemsFilter
add filter predicate dbo.fn_ordershipmentitemsfilter_predicate(FK_OrderShipmentID) 
on dbo.OrderShipmentItems
with (state = on);

GO

execute as user = 'SalesRep1';
select * from dbo.Orders; 
select * from dbo.OrderShipments; 
select * from dbo.OrderShipmentItems; 
revert;

GO

execute as user = 'SalesRep2';
select * from dbo.Orders; 
select * from dbo.OrderShipments; 
select * from dbo.OrderShipmentItems; 
revert;

GO

execute as user = 'Manager';
select * from dbo.Orders; 
select * from dbo.OrderShipments; 
select * from dbo.OrderShipmentItems; 
revert;

GO
这带来了一些问题: -随着子级的增加,谓词的复杂性增加 -更改根表上的安全规则需要更改所有子表的规则

有没有办法解决这些问题


谢谢

您可以在视图中使用handle row policy(例如与schema policy结合使用),但如果类型越多,复杂性就会增加。是否有办法让安全谓词在与初始查询相同的上下文中运行?查询/连接谓词中的其他表似乎不会被它们各自的安全谓词过滤。通过db引擎处理安全性(行策略)是不常见的。这是应用程序的任务。您可以创建具有权限/角色的表,动态处理数据连接和权限,或者创建过程集合,添加执行过程的权限,并在过程内进行选择和筛选。