在存储过程中通过用户的默认架构进行访问时,在SQL Server中切换用户失败

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在存储过程中通过用户的默认架构进行访问时,在SQL Server中切换用户失败相关的知识,希望对你有一定的参考价值。

我正在尝试在MS SQL Server 2014 DB中实现共享API。在该体系结构中,模式应该具有类似的结构并使用dbo拥有的共享API,同时公开自己的API。为了在不限定对象名称的情况下相互调用,EXECUTE AS USER语句用于上下文切换到当前用户的某个默认模式。

问题在于:虽然使用用户上下文切换的即时访问工作正常(例如EXECUTE AS USER后跟SELECT * from test_tbl;),但存储过程中通过默认模式的访问失败,错误为Msg 208, Level 16, State 1

在发布我的问题之前,我尝试了很多实验和测试,并在几天内搜索了MSDN,Web和SQL论坛的任何线索,但没有运气。

用于复制的脚本(<MDF><LDF>需要使用适当的文件路径替换):

-- DB creation
CREATE DATABASE [test_sql]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'test_sql', FILENAME = N'<MDF>' , SIZE = 5120KB , FILEGROWTH = 1024KB )
 LOG ON 
( NAME = N'test_sql_log', FILENAME = N'<LDF>' , SIZE = 2048KB , FILEGROWTH = 10%)
 COLLATE Cyrillic_General_CI_AS
GO
ALTER DATABASE [test_sql] SET COMPATIBILITY_LEVEL = 120
GO
ALTER DATABASE [test_sql] SET ANSI_NULL_DEFAULT OFF 
GO
ALTER DATABASE [test_sql] SET ANSI_NULLS OFF 
GO
ALTER DATABASE [test_sql] SET ANSI_PADDING OFF 
GO
ALTER DATABASE [test_sql] SET ANSI_WARNINGS OFF 
GO
ALTER DATABASE [test_sql] SET ARITHABORT OFF 
GO
ALTER DATABASE [test_sql] SET AUTO_CLOSE OFF 
GO
ALTER DATABASE [test_sql] SET AUTO_SHRINK OFF 
GO
ALTER DATABASE [test_sql] SET AUTO_CREATE_STATISTICS ON
GO
ALTER DATABASE [test_sql] SET AUTO_UPDATE_STATISTICS ON 
GO
ALTER DATABASE [test_sql] SET CURSOR_CLOSE_ON_COMMIT OFF 
GO
ALTER DATABASE [test_sql] SET CURSOR_DEFAULT  GLOBAL 
GO
ALTER DATABASE [test_sql] SET CONCAT_NULL_YIELDS_NULL OFF 
GO
ALTER DATABASE [test_sql] SET NUMERIC_ROUNDABORT OFF 
GO
ALTER DATABASE [test_sql] SET QUOTED_IDENTIFIER OFF 
GO
ALTER DATABASE [test_sql] SET RECURSIVE_TRIGGERS OFF 
GO
ALTER DATABASE [test_sql] SET  DISABLE_BROKER 
GO
ALTER DATABASE [test_sql] SET AUTO_UPDATE_STATISTICS_ASYNC OFF 
GO
ALTER DATABASE [test_sql] SET DATE_CORRELATION_OPTIMIZATION OFF 
GO
ALTER DATABASE [test_sql] SET PARAMETERIZATION SIMPLE 
GO
ALTER DATABASE [test_sql] SET READ_COMMITTED_SNAPSHOT OFF 
GO
ALTER DATABASE [test_sql] SET  READ_WRITE 
GO
ALTER DATABASE [test_sql] SET RECOVERY FULL 
GO
ALTER DATABASE [test_sql] SET  MULTI_USER 
GO
ALTER DATABASE [test_sql] SET PAGE_VERIFY CHECKSUM  
GO
ALTER DATABASE [test_sql] SET TARGET_RECOVERY_TIME = 0 SECONDS 
GO
ALTER DATABASE [test_sql] SET DELAYED_DURABILITY = DISABLED 
GO
USE [test_sql]
GO
IF NOT EXISTS (SELECT name FROM sys.filegroups WHERE is_default=1 AND name = N'PRIMARY') ALTER DATABASE [test_sql] MODIFY FILEGROUP [PRIMARY] DEFAULT
GO

-- Srv login, DB user and schema creation
CREATE LOGIN [test_usr_login] WITH PASSWORD=N'test_usr_login', DEFAULT_DATABASE=[test_sql], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
CREATE USER [test_usr] FOR LOGIN [test_usr_login] WITH DEFAULT_SCHEMA=[test_schema]
GO
CREATE SCHEMA [test_schema] AUTHORIZATION [test_usr]
GO

-- Table and stored proc creation
IF OBJECT_id("[test_schema].[test_tbl]", "U") IS NOT NULL
DROP TABLE [test_schema].[test_tbl];
GO
CREATE TABLE [test_schema].[test_tbl](
    [tc] [nchar](10) NULL
) ON [PRIMARY]
GO

IF OBJECT_id("[dbo].[TA]", "P") IS NOT NULL
DROP PROCEDURE [dbo].[TA];
GO
CREATE PROCEDURE [dbo].[TA] AS BEGIN
    SET NOCOUNT ON;
  SELECT * FROM 
  (VALUES
  ('CURRENT_USER', CURRENT_USER),
  ('SCHEMA_NAME', SCHEMA_NAME()),
  ('have_UNqualified_select', cast(HAS_PERMS_BY_NAME("[test_tbl]", "OBJECT", "SELECT") as nchar(10))),
   ('have_qualified_select', cast(HAS_PERMS_BY_NAME("[test_schema].[test_tbl]", "OBJECT", "SELECT") as nchar(10)))
  ) AS tmptbl([key], val); -- select permissions fro [test_tbl] of the current user
  SELECT tc as qualified_tc FROM [test_schema].[test_tbl]; -- qualified select
  SELECT tc as UNqualified_tc from [test_tbl]; -- unqualified select fails with Msg 208
END
GO

GRANT EXECUTE ON [dbo].[TA] TO [test_usr]
GO

测试脚本:

USE [test_sql]
GO
DECLARE @return_value int
execute as login = N'test_usr_login'; -- even when logged in with test_usr_logn, Msg 208 occurs
EXEC    @return_value = [dbo].[TA]
revert
SELECT  'Return Value' = @return_value
GO

输出消息:

消息208,级别16,状态1,过程TA,行14无效的对象名称't​​est_tbl'。

(1排受影响)

输出结果:

key val
CURRENT_USER    test_usr
SCHEMA_NAME test_schema
have_UNqualified_select 1         
have_qualified_select   1         

我很感激任何能够为所述问题的解决方案带来光明的人。

答案

问题出在这里:虽然使用用户上下文切换的立即访问工作正常(例如EXECUTE AS USER后跟来自test_tbl的SELECT *;),存储过程中通过默认模式的访问失败,错误消息为208,级别16,状态1。

这里的问题是您不知道SQL Server如何解析非限定对象名称。

当您执行普通sql并使用对象而不指定其架构时,将检查第一个用户default schema,如果找不到对象,则检查dbo架构。如果甚至在dbo中找不到该对象,则会引发错误。

它与存储过程有所不同。如果未指定schema,则首先检查sp的模式,如果未找到object,则检查dbo模式,如果再次找不到,则引发错误。在存储过程中从不检查User default schema

以上是关于在存储过程中通过用户的默认架构进行访问时,在SQL Server中切换用户失败的主要内容,如果未能解决你的问题,请参考以下文章

SQLServer中通过脚本内容查找存储过程

在Nginx中通过phpmyadmin将20mb SQL文件导入MySQL时,“连接已重置”

在vscode中通过sql toos连接mysql时看不到数据库中的表

有无参数之存储过程

SQL Server 可以根据用户或用户角色在两个架构之间进行仲裁吗?

在 Spark SQL 中通过 COALESCE 减少分区