TSQL - 执行CLR权限

发布于 2024-09-30 23:07:12 字数 2384 浏览 2 评论 0原文

我从 CLR(.net 程序集)获得了一个 sql 过程,执行时返回错误

Msg 6522, Level 16, State 1, Procedure sp_HelloWorld, Line 0
A .NET Framework error occurred during execution of user defined routine or aggregate 'sp_HelloWorld': 
System.Security.SecurityException: Request for the permission of type 'System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
System.Security.SecurityException: 
   at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
   at System.Security.PermissionSet.Demand()
   at System.Data.Common.DbConnectionOptions.DemandPermission()
   at System.Data.SqlClient.SqlConnection.PermissionDemand()
   at System.Data.SqlClient.SqlConnectionFactory.PermissionDemand(DbConnection outerConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at HelloWorld.SQLCLR.HelloWorld()

这是我的 SQL 脚本

go
drop procedure HelloWorld
drop assembly HelloWorld
GO

create assembly HelloWorld from 'F:\HelloWorld.dll'
with permission_set = safe
Go
create procedure sp_HelloWorld
as external name HelloWorld.[HelloWorld.SQLCLR].HelloWorld
go
exec sp_HelloWorld

,这是我的类(程序集)

using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Security.Permissions;
using System.Data;

namespace HelloWorld
{
    public class SQLCLR
    {
        [Microsoft.SqlServer.Server.SqlProcedure]
        public static void HelloWorld()
        {
            string connectString1 = @"Data Source=localhost;Initial Catalog=ItemData;Integrated Security=True";

            SqlClientPermission permission = new SqlClientPermission(PermissionState.None);
            permission.Add(connectString1, "", KeyRestrictionBehavior.AllowOnly);
            permission.PermitOnly();
            SqlConnection sqlcon = new SqlConnection(connectString1);
            sqlcon.Open();
            SqlCommand sqlcmd = new SqlCommand("SELECT Top 1 * FROM ItemData.dbo.Item", sqlcon);
            SqlDataReader reader = sqlcmd.ExecuteReader();
            SqlContext.Pipe.Send(reader);
            sqlcon.Close();
        }
    }
}

I got a sql procedure from a CLR (.net Assembly) that when executed returns an error

Msg 6522, Level 16, State 1, Procedure sp_HelloWorld, Line 0
A .NET Framework error occurred during execution of user defined routine or aggregate 'sp_HelloWorld': 
System.Security.SecurityException: Request for the permission of type 'System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
System.Security.SecurityException: 
   at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
   at System.Security.PermissionSet.Demand()
   at System.Data.Common.DbConnectionOptions.DemandPermission()
   at System.Data.SqlClient.SqlConnection.PermissionDemand()
   at System.Data.SqlClient.SqlConnectionFactory.PermissionDemand(DbConnection outerConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at HelloWorld.SQLCLR.HelloWorld()

This is my SQL script

go
drop procedure HelloWorld
drop assembly HelloWorld
GO

create assembly HelloWorld from 'F:\HelloWorld.dll'
with permission_set = safe
Go
create procedure sp_HelloWorld
as external name HelloWorld.[HelloWorld.SQLCLR].HelloWorld
go
exec sp_HelloWorld

and this is my Class (Assembly)

using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Security.Permissions;
using System.Data;

namespace HelloWorld
{
    public class SQLCLR
    {
        [Microsoft.SqlServer.Server.SqlProcedure]
        public static void HelloWorld()
        {
            string connectString1 = @"Data Source=localhost;Initial Catalog=ItemData;Integrated Security=True";

            SqlClientPermission permission = new SqlClientPermission(PermissionState.None);
            permission.Add(connectString1, "", KeyRestrictionBehavior.AllowOnly);
            permission.PermitOnly();
            SqlConnection sqlcon = new SqlConnection(connectString1);
            sqlcon.Open();
            SqlCommand sqlcmd = new SqlCommand("SELECT Top 1 * FROM ItemData.dbo.Item", sqlcon);
            SqlDataReader reader = sqlcmd.ExecuteReader();
            SqlContext.Pipe.Send(reader);
            sqlcon.Close();
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

后eg是否自 2024-10-07 23:07:12

问题很简单,您正在尝试访问程序集中标记为“SAFE”的外部资源。访问外部资源需要将程序集设置为至少EXTERNAL_ACCESS(在某些情况下UNSAFE)。但是,查看您的代码,您只是尝试连接到本地实例,在这种情况下,有一种更简单(更快)的方法可以实现此目的:使用 "Context Connection = true;" 作为连接字符串。

上下文连接是与当前进程/会话的直接连接,有时也称为进程内连接。使用上下文连接的好处是:

  • 可以在标记为 SAFE 的程序集中完成
  • 对本地临时对象(临时表和临时过程,名称均以单个 # 开头的访问) > 而不是双 ##
  • 访问 SET CONTEXT_INFOCONTEXT_INFO()
  • 无连接启动开销

另外:

  • 是否使用进程内,上下文连接或常规/外部连接,您不需要使用 SqlClientPermission 正式请求权限,
  • 您应该始终通过调用其 Dispose() 方法来清理外部资源。并非所有对象都具有此功能,但 SqlConnectionSqlCommandSqlDataReader 肯定具有。人们通常将一次性对象包装在 using() 块中,因为它是一个编译器宏,扩展为调用 Dispose() 方法的 try/finally 结构在 finally 中确保即使发生错误,它也会被调用。
  • 许多/大多数一次性对象的 Dispose() 方法会自动处理对 Close() 的调用,因此您通常不需要调用 Close() > 明确地。

您的代码应如下所示:

[Microsoft.SqlServer.Server.SqlProcedure]
public static void HelloWorld()
{
  using (SqlConnection sqlcon = new SqlConnection("Context Connection = true;")
  {
    using (SqlCommand sqlcmd = new SqlCommand("SELECT Top 1 * FROM ItemData.dbo.Item",
               sqlcon))
    {
      sqlcon.Open();

      using (SqlDataReader reader = sqlcmd.ExecuteReader())
      {
        SqlContext.Pipe.Send(reader);
      }
    }
  }
}

The problem is simply that you are attempting to access an external resource in an Assembly that is marked as SAFE. Accessing external resources requires setting the Assembly to at least EXTERNAL_ACCESS (and in some cases UNSAFE). However, looking at your code, you are simply trying to connect to the local instance, and in that case there is a far easier (and faster) means of doing this: using "Context Connection = true;" as the ConnectionString.

The Context Connection is a direct connection to the current process / session, and it is sometimes referred to as the in-process connection. The benefits of using the Context Connection are:

  • can be done in Assemblies marked as SAFE
  • access to local temporary objects (temp tables and temp procedures, both with names starting with a single # instead of double ##)
  • access to SET CONTEXT_INFO and CONTEXT_INFO()
  • no connection startup overhead

Also:

  • whether you use the in-process, Context Connection or a regular / external connection, you do not need to formally request permission using SqlClientPermission
  • you should always clean up external resources by calling their Dispose() method. Not all objects have this, but SqlConnection, SqlCommand, and SqlDataReader certainly do. It is typical for people to wrap disposable objects in a using() block as it is a compiler macro that expands to a try / finally structure that calls the Dispose() method in the finally to ensure that it is called, even if an error occurs.
  • The Dispose() method of many / most disposable objects automatically handles the call to Close() so you usually do not need to call Close() explicitly.

Your code should look as follows:

[Microsoft.SqlServer.Server.SqlProcedure]
public static void HelloWorld()
{
  using (SqlConnection sqlcon = new SqlConnection("Context Connection = true;")
  {
    using (SqlCommand sqlcmd = new SqlCommand("SELECT Top 1 * FROM ItemData.dbo.Item",
               sqlcon))
    {
      sqlcon.Open();

      using (SqlDataReader reader = sqlcmd.ExecuteReader())
      {
        SqlContext.Pipe.Send(reader);
      }
    }
  }
}
我不吻晚风 2024-10-07 23:07:12

我只是想在此添加我的两种感觉。我正在做一些非常相似的事情,但我遇到了同样的错误。这是我发现的,但是 b/c 我没有这种级别的数据库访问权限,我无法测试它。

最简单(尽管 MSDN 不建议仅喷射 CLR 过程来运行)
就是设置权限级别为External_Access...

SQL Server 主机策略级别权限集代码访问权限集
SQL Server 主机授予程序集的安全权限
策略级别由指定的权限集决定
创建装配体。共有三个权限集:SAFE、
EXTERNAL_ACCESS 且不安全。

权限级别在 CLR 项目的属性页上设置
,数据库选项卡-设置权限级别-外部,设置AAssembly
所有者-dbo,并运行 tsql 'ALTER DATABASE DataBaseName SET TRUSTWORTHY
ON' 这将完成工作! - SmtpClient 将正常工作...
然后正确执行并使用强名称密钥文件对程序集进行签名...

完整帖子在此。 ..

I just wanted to add my two sense to this. I'm doing something very similiar and I'm getting the same error. Here is what I found, however b/c I don't have this level of access to the DB I can't test it.

Easiest( although not MSDN recommended just to jet a CLR proc to run)
is to set the permission level to External_Access...

SQL Server Host Policy Level Permission Sets The set of code access
security permissions granted to assemblies by the SQL Server host
policy level is determined by the permission set specified when
creating the assembly. There are three permission sets: SAFE,
EXTERNAL_ACCESS and UNSAFE.

The permision level is set on the properties pages of the CLR project
, database tab - set Permission Level-External, set Aassembly
Owner-dbo, and run tsql 'ALTER DATABASE DataBaseName SET TRUSTWORTHY
ON' This will get the job DONE! - and the SmtpClient wiill work ok...
Then do it right and Sign the Assenbly with a Strong name Key file...

Full Post Here...

人生百味 2024-10-07 23:07:12

您是否已将 DB 设置为 Trustworth ON 并启用了 clr?

试试这个

sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO

ALTER DATABASE [YourDatabase] SET TRUSTWORTHY ON
GO

我有一个指南这里如何使用 CLR 存储过程可能会有所帮助。

Have you set your DB set to Trusrtworth ON and enabled clr?

Try this

sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO

ALTER DATABASE [YourDatabase] SET TRUSTWORTHY ON
GO

I have a guide here on how to use CLR Stored Procedures that might help.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文