Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL Server所有权链接对ALTER不起作用吗?_Sql Server_Database Design - Fatal编程技术网

Sql server SQL Server所有权链接对ALTER不起作用吗?

Sql server SQL Server所有权链接对ALTER不起作用吗?,sql-server,database-design,Sql Server,Database Design,我遇到过这样的情况,SQL Server所有权链接似乎不起作用——或者我遗漏了什么 我有两个模式:Schema1和Schema2 在Schema1中,我只有SELECT权限,而在Schema2中,我只有EXEC权限 我在Schema2中调用一个存储过程,它将记录插入Schema1中的表中 由于所有权链接,这很好(即使我在Schema1中没有INSERT权限) 现在,当我调用另一个存储过程(在插入之前关闭表中的标识列)时,我得到一个错误: Msg 1088, Level 16, State 11,

我遇到过这样的情况,SQL Server所有权链接似乎不起作用——或者我遗漏了什么

我有两个模式:
Schema1
Schema2

Schema1
中,我只有
SELECT
权限,而在
Schema2
中,我只有
EXEC
权限

我在
Schema2
中调用一个存储过程,它将记录插入
Schema1
中的表中

由于所有权链接,这很好(即使我在
Schema1
中没有
INSERT
权限)

现在,当我调用另一个存储过程(在插入之前关闭表中的标识列)时,我得到一个错误:

Msg 1088, Level 16, State 11, Procedure Schema2.AddRecordWithSpecificId, Line 7 [Batch Start Line 60]
Cannot find the object "Schema1.MyTable" because it does not exist or you do not have permissions.
如果我授予
ALTER
Schema1
的权限,它可以正常工作-但为什么这是必要的?为什么模式链接在这种情况下不起作用

复制问题的脚本:

CREATE DATABASE OwnershipChainingTest
GO

USE OwnershipChainingTest
GO

CREATE SCHEMA Schema1 AUTHORIZATION [dbo]
GO
CREATE SCHEMA Schema2 AUTHORIZATION [dbo]
GO

CREATE TABLE Schema1.MyTable
(
    Id int IDENTITY(1,1) NOT NULL,
    Title varchar(50) NOT NULL
)
GO

CREATE PROCEDURE Schema2.AddRecord
    @title nvarchar(100) 
AS
BEGIN
    INSERT INTO Schema1.MyTable (Title) 
    VALUES (@title)
END
GO

CREATE PROCEDURE Schema2.AddRecordWithSpecificId
    @id int,
    @title nvarchar(100) 
AS
BEGIN
    SET IDENTITY_INSERT Schema1.MyTable ON

    INSERT INTO Schema1.MyTable (Id, Title) 
    VALUES (@id, @title)

    SET IDENTITY_INSERT Schema1.MyTable OFF
END
GO

CREATE USER MyUser WITHOUT LOGIN
GO

CREATE ROLE MyRole AUTHORIZATION [dbo]
GO

EXEC sp_addrolemember MyRole, MyUser
GO

-- With this it works: GRANT SELECT, ALTER ON Schema::Schema1 TO MyRole
GRANT SELECT ON Schema::Schema1 TO MyRole
GO
GRANT EXEC ON Schema::Schema2 TO MyRole
GO

EXEC AS user = 'MyUser'

EXEC Schema2.AddRecord 'hello1'
GO

-- This causes an error
EXEC Schema2.AddRecordWithSpecificId 42, 'hello2'
GO

REVERT;
--SELECT CURRENT_USER

SELECT * FROM Schema1.MyTable

USE MASTER
DROP DATABASE OwnershipChainingTest
GO

所有权链接仅适用于DML
SET IDENTITY\u INSERT本质上是一个DDL操作,这就是为什么它至少需要表上的
ALTER
权限

允许仅具有执行权限的最低权限用户运行proc的一个好方法是使用基于具有
ALTER
权限的用户的证书对proc进行签名:

--create certificate and sign proc
CREATE CERTIFICATE AddRecordWithSpecificIdCert
   ENCRYPTION BY PASSWORD = 'temporary password'
   WITH SUBJECT = 'Allow ALTER on Schema1';
ADD SIGNATURE TO  Schema2.AddRecordWithSpecificId BY CERTIFICATE AddRecordWithSpecificIdCert WITH PASSWORD = 'temporary password';

--remove ephemeral private key
ALTER CERTIFICATE AddRecordWithSpecificIdCert REMOVE PRIVATE KEY;

--create a user from certificate with the needed permissions
CREATE USER AddRecordWithSpecificIdCertUser FROM CERTIFICATE AddRecordWithSpecificIdCert;
GRANT ALTER ON SCHEMA::Schema1 TO AddRecordWithSpecificIdCertUser;
GO

--this test now works
EXEC AS user = 'MyUser';
GO
EXEC Schema2.AddRecordWithSpecificId 42, 'hello2'
GO
REVERT;
GO

所有权链接仅适用于DML
SET IDENTITY\u INSERT本质上是一个DDL操作,这就是为什么它至少需要表上的
ALTER
权限

允许仅具有执行权限的最低权限用户运行proc的一个好方法是使用基于具有
ALTER
权限的用户的证书对proc进行签名:

--create certificate and sign proc
CREATE CERTIFICATE AddRecordWithSpecificIdCert
   ENCRYPTION BY PASSWORD = 'temporary password'
   WITH SUBJECT = 'Allow ALTER on Schema1';
ADD SIGNATURE TO  Schema2.AddRecordWithSpecificId BY CERTIFICATE AddRecordWithSpecificIdCert WITH PASSWORD = 'temporary password';

--remove ephemeral private key
ALTER CERTIFICATE AddRecordWithSpecificIdCert REMOVE PRIVATE KEY;

--create a user from certificate with the needed permissions
CREATE USER AddRecordWithSpecificIdCertUser FROM CERTIFICATE AddRecordWithSpecificIdCert;
GRANT ALTER ON SCHEMA::Schema1 TO AddRecordWithSpecificIdCertUser;
GO

--this test now works
EXEC AS user = 'MyUser';
GO
EXEC Schema2.AddRecordWithSpecificId 42, 'hello2'
GO
REVERT;
GO

错误是什么?Msg 1088,级别16,状态11,过程Schema2.AddRecordWithSpecificId,第7行[批处理开始行60]找不到对象“Schema1.MyTable”,因为它不存在或您没有权限@刻痕McDermaid@ThomasBoelSigurdsson我回答了你的问题,但是如果不同的用户同时执行<代码> SETIGIDENTION PROC,请务必考虑并发含义。DanGuzman谢谢。这也是我所想/担心的——我只是在任何地方都找不到它的描述。这是一个具有并发含义的好观点。然而,我确实需要能够偶尔指定一个id,即使通常id是从identity列中提取的。是否有一种方法可以从表外部的序列中绘制id?例如,你能不能有一个类似于标识列的东西,你可以从中临时提取一个值?@ThomasBoelSigurdsson,我认为对于偶尔的临时值,a比
IDENTITY
更合适<代码>创建序列Schema1.MyTable_序列作为bigint,从1开始;创建表Schema1.MyTable(Id int NOT NULL约束DF_MyTable_序列Schema1.MyTable_序列的默认下一个值,…
错误是什么?Msg 1088,级别16,状态11,过程Schema2.AddRecordWithSpecificId,第7行[批处理起始行60]找不到对象“Schema1.MyTable”因为它不存在或者您没有权限。@Nick。McDermaid@ThomasBoelSigurdsson我回答了你的问题,但是如果不同的用户同时执行<代码> SETIGIDENTION PROC,我一定要考虑并发的含义。“谢谢DanGuzman。谢谢你。这也是我所想的/害怕的——我就是找不到它。ribed anywhere。这是一个具有并发含义的好观点。然而,我确实需要能够偶尔指定一个id,即使通常id将从identity列中提取。是否有一种方法可以从表外部的序列中提取id?例如,您是否可以使用类似于identity列的方法来提取id在临时基础上从中提取值?@ThomasBoelSigurdsson,我认为a比
IDENTITY
更适合偶尔的临时值。
CREATE SEQUENCE Schema1.MyTable\u SEQUENCE AS bigint从1开始;CREATE TABLE Schema1.MyTable(Id int NOT NULL CONSTRAINT DF_MyTable_Sequence Schema1.MyTable_Sequence的默认下一个值,…
为什么要删除证书上的私钥?如果/当此过程更改时,它将需要退出,删除私钥意味着您必须创建一个新证书,从证书中创建一个新用户,向该用户授予权限,然后再次为进程签名。@BenThul,虽然不是必需的,但我通常为每个已签名的模块使用临时证书和用户,并在每次重新创建或更改对象时重新创建它们。我发现这简化了证书和机密的管理,使权限脚本与进程一起受源代码控制。我还有一个实用程序y proc以便于使用,带有proc名称和权限脚本的参数。proc在部署期间使用命名约定(如我的回答中的示例)生成并执行签名脚本。为什么要删除证书上的私钥?如果/当此proc发生更改时,它将需要退出,删除私钥意味着我必须创建一个新的证书,从证书中创建一个新用户,授予该用户权限,然后最终再次对进程进行签名。@BenThul,虽然不是必需的,但我通常为每个已签名的模块使用一个临时证书和用户,并在每次重新创建或更改对象时重新创建它们。我发现这简化了证书和秒的管理rets,将权限脚本与proc一起置于源代码控制之下。我还有一个实用程序proc,用于提供proc名称和权限脚本的参数。proc在部署期间使用命名约定(如我的答案中的示例)生成并执行签名脚本。