如何将凭据映射到 SQL 服务器中的 SQLCLR 程序集?

How do I map a credential to a SQLCLR assembly in SQL Server?

我在 SQL 服务器中有一个 CLR 程序集,我需要继承特定帐户的权限。 CLR 函数基本上只是抓取一个网页,然后 returns 以这种方式将其 SQL:

    [SqlFunction]
    [return: SqlFacet(MaxSize = -1)]
    public static SqlChars Get(SqlChars H, SqlChars url)
    {
        var client = new WebClient();

        client.Credentials = CredentialCache.DefaultNetworkCredentials;

        AddHeader(H, client);
        return new SqlChars(
                client.DownloadString(
                    Uri.EscapeUriString(url.ToSqlString().Value)
                    ).ToCharArray());
    }

我希望它能够使用特定帐户详细信息通过 NTLM 进行身份验证。这在 SQL 之外的 C# 程序中工作正常,但作为 CLR 函数它只是 returns 401 未经授权的消息,这是因为 DefaultNetworkCredentials 是 SQL 服务器服务帐户的消息(我通过将服务设置为使用我的凭据来确认这一点,然后 CLR 完美运行)

我的理解是,这样做的方法是创建一个 Credential in SQL Server with that account's details, since that's what the documentation 说:

Credentials provide a way to allow SQL Server Authentication users to have an identity outside of SQL Server. This is primarily used to execute code in Assemblies with EXTERNAL_ACCESS permission set.

我可以做到,但我似乎无法找到任何方法将该凭证映射到程序集。我该怎么做?

我不确定 SQL 服务器中的凭据是否确实以这种方式工作(该文档页面中描述的方式)。但是,即使它们可以通过 SQLCLR 模块用于外部操作,也不会通过向程序集分配任何东西来实现。 SQL 服务器中的凭据映射到 SQL 服务器登录。因此,您可以将凭据映射到一个或多个 SQL 服务器登录,这些登录将执行 SQL 基于 CLR 的模块。

并且,如果您需要外部操作使用默认以外的安全上下文 — SQL 服务器服务帐户 — 那么您需要激活 Impersonation within the .NET code. Doing that will assume the security context of the Windows account that is executing the SQLCLR-based module within SQL Server. SQL Server logins are not Windows accounts which is why they typically cannot do Impersonation within the .NET code. Perhaps by mapping a T-SQL Credential to a SQL Server login it would then be possible (I have tested this and it does not work; the documentation is very much incorrect; I will submit a correction for it on GitHub). Please keep in mind that the WindowsIdentity and WindowsImpersonationContext 对象是一次性的,因此您需要将它们包装在 using(...){} 构造中,或者至少调用 try/catch/finallytry/finally 块的 finally 部分中的 Dispose() 方法。如果您使用 Windows Auth 登录,那么您可以进行此模拟,但它将模拟正在执行该模块的任何登录,我假设这些帐户可以是不同的帐户(即不总是您的帐户),因此他们都需要访问外部资源。

另一种选择是通过 new NetworkCredential() 在 .NET 代码中直接提供凭据。这样做不仅适用于 SQL 服务器登录,而且允许单个帐户连接,因为(您当然 可以 从列表中查找凭据以使用不同的凭据基于某些条件,但这至少允许通过单个帐户访问远程资源。