适用于: .NET Framework
.NET
.NET Standard
本文介绍如何通过 SqlClient 从 .NET 应用程序使用 Microsoft Entra 身份验证连接到 Azure SQL 数据源。
注意
虽然 Microsoft Entra ID 是 Azure Active Directory (Azure AD) 的新名称,但为了防止中断现有环境,Azure AD 仍保留在一些硬编码的元素中,例如 UI 字段、连接提供程序、错误代码和 cmdlet。 在本文中,这两个名称可以互换。
概述
Microsoft Entra 身份验证使用 Microsoft Entra ID 中的标识访问 Azure SQL 数据源(例如 Azure SQL 数据库、Azure SQL 托管实例和 Azure Synapse Analytics)。 利用 Microsoft.Data.SqlClient 命名空间,客户端应用程序可以在连接到 Azure SQL 数据库和 Azure SQL 托管实例时在不同的身份验证模式下指定 Microsoft Entra 凭据。 要结合使用 Microsoft Entra 与 Azure SQL,须使用 Azure SQL 配置并管理 Microsoft Entra 身份验证。
设置连接字符串中的 Authentication
连接属性时,客户端可以根据提供的值选择首选 Microsoft Entra 身份验证模式:
最早的 Microsoft.Data.SqlClient 版本支持在 .NET Framework、.NET Core 和 .NET Standard 上使用 。 它还支持在 .NET Framework 上使用
Active Directory Integrated
身份验证和Active Directory Interactive
身份验证。从 Microsoft.Data.SqlClient 2.0.0 开始,对 身份验证和
Active Directory Integrated
身份验证的支持扩展到 .NET Framework、.NET Core 和 .NET Standard。在 SqlClient 2.0.0 中还添加了新的
Active Directory Service Principal
身份验证模式。 它利用客户端 ID 和服务主体标识的机密来完成身份验证。Microsoft.Data.SqlClient 2.1.0 中添加了更多身份验证模式,包括 和
Active Directory Device Code Flow
(也称为Active Directory Managed Identity
)。 这些新模式允许应用程序获取连接到服务器的访问令牌。
有关 Microsoft Entra 身份验证的其他信息,请参阅使用 Microsoft Entra 身份验证。
设置 Microsoft Entra 身份验证
应用程序使用 Microsoft Entra 身份验证连接到 Azure SQL 数据源时需要提供有效的身份验证模式。 下表列出了支持的身份验证模式。 应用程序通过使用连接字符串中的 Authentication
连接属性指定一种模式。
值 | 说明 | Microsoft.Data.SqlClient 版本 |
---|---|---|
Active Directory 密码 | 使用用户名和密码对 Microsoft Entra 标识进行身份验证。 | 1.0+ |
Active Directory 已集成 | 使用集成 Windows 身份验证 (IWA) 对 Microsoft Entra 标识进行身份验证 | 2.0.0+1 |
Azure Active 交互式 | 使用交互式身份验证对 Microsoft Entra 标识进行身份验证 | 2.0.0+1 |
Active Directory 服务主体 | 使用客户端 ID 和机密对 Microsoft Entra 服务主体进行身份验证 | 2.0.0+ |
Active Directory 设备代码流 | 使用设备代码流模式对 Microsoft Entra 标识进行身份验证 | 2.1.0+ |
Active Directory 托管标识、 Active Directory MSI |
使用 Microsoft Entra 系统分配或用户分配的托管标识进行身份验证。 | 2.1.0+ |
Active Directory 默认 | 使用无密码的非交互式机制(包括托管标识、Visual Studio Code、Visual Studio、Azure CLI 等),对 Microsoft Entra 标识进行身份验证。 | 3.0.0+ |
Active Directory 工作负载标识 | 使用联合用户分配的托管标识对 Microsoft Entra 标识进行身份验证,以便从支持 Workload Identity 的 Azure 客户端环境连接到 SQL 数据库。 | 5.2.0+ |
1 在 Microsoft.Data.SqlClient 2.0.0 之前, 和 Active Directory Integrated
身份验证模式仅在 .NET Framework 上受支持。
使用密码身份验证
Active Directory Password
身份验证模式支持本机或联合 Microsoft Entra 用户使用 Microsoft Entra ID 对访问 Azure 数据源进行身份验证。 使用此模式时,必须在连接字符串中提供用户凭据。 下面的示例演示如何使用 Active Directory Password
身份验证。
// Use your own server, database, user ID, and password.
string ConnectionString = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Password; Encrypt=True; Database=testdb;"
+ "User Id=user@domain.com; Password=<password>";
using (SqlConnection conn = new SqlConnection(ConnectionString)) {
conn.Open();
}
使用集成身份验证
如果使用 Active Directory Integrated
身份验证模式,必须将本地 Active Directory 实例与云中的 Microsoft Entra ID 联合。 例如,可以使用 Active Directory 联合身份验证服务 (AD FS) 进行联合。
在此模式下登录到加入域的计算机时,可以访问 Azure SQL 数据源,而无需提供凭据。 不能在 .NET Framework 应用程序的连接字符串中指定用户名和密码。 在 .NET Core 和 .NET Standard 应用程序的连接字符串中,用户名是可选的。 在此模式下,不能设置 SqlConnection 的 Credential
属性。
以下代码片段是使用 Active Directory Integrated
身份验证时的一个示例。
// Use your own server and database.
string ConnectionString1 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Integrated; Encrypt=True; Database=testdb";
using (SqlConnection conn = new SqlConnection(ConnectionString1)) {
conn.Open();
}
// User ID is optional for .NET Core and .NET Standard.
string ConnectionString2 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Integrated; Encrypt=True; Database=testdb;"
+ "User Id=user@domain.com";
using (SqlConnection conn = new SqlConnection(ConnectionString2)) {
conn.Open();
}
使用交互式身份验证
Active Directory Interactive
身份验证支持用于连接到 Azure SQL 数据源的多重身份验证技术。 如果在连接字符串中提供此身份验证模式,则显示 Azure 身份验证屏幕,并要求用户输入有效凭据。 不能在连接字符串中指定密码。
在此模式下,不能设置 SqlConnection 的 Credential
属性。 在 Microsoft.Data.SqlClient 2.0.0 和更高版本中,在交互模式下,允许在连接字符串中使用用户名。
下面的示例演示如何使用 Active Directory Interactive
身份验证。
// Use your own server, database, and user ID.
// User ID is optional.
string ConnectionString1 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Interactive; Encrypt=True;"
+ "Database=testdb; User Id=user@domain.com";
using (SqlConnection conn = new SqlConnection(ConnectionString1)) {
conn.Open();
}
// User ID is not provided.
string ConnectionString2 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Interactive; Encrypt=True;"
+ "Database=testdb";
using (SqlConnection conn = new SqlConnection(ConnectionString2)) {
conn.Open();
}
使用服务主体身份验证
在 Active Directory Service Principal
身份验证模式下,客户端应用程序可通过提供客户端 ID 和服务主体标识的机密来连接到 Azure SQL 数据源。 服务主体身份验证涉及:
- 使用机密设置应用注册。
- 向 Azure SQL 数据库实例中的应用授予权限。
- 使用正确的凭据连接。
下面的示例演示如何使用 Active Directory Service Principal
身份验证。
// Use your own server, database, app ID, and secret.
string ConnectionString = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Service Principal; Encrypt=True;"
+ "Database=testdb; User Id=AppId; Password=<password>";
using (SqlConnection conn = new SqlConnection(ConnectionString)) {
conn.Open();
}
使用设备代码流身份验证
在适用于 .NET 的 Microsoft 身份验证库 (MSAL.NET) 中,Active Directory Device Code Flow
身份验证使客户端应用程序可以从不具备交互式 Web 浏览器的设备和操作系统连接到 Azure SQL 数据源。 在另一台设备上执行交互式身份验证。 有关设备代码流身份验证的详细信息,请参阅 OAuth 2.0 设备代码流。
在此模式下,不能设置 Credential
的 SqlConnection
属性。 此外,不能在连接字符串中指定用户名和密码。
以下代码片段是使用 Active Directory Device Code Flow
身份验证的一个示例。
注意
Active Directory Device Code Flow
的超时默认为连接的 Connect Timeout
设置。 请确保指定 Connect Timeout
,以便有足够的时间完成设备代码流身份验证过程。
// Use your own server and database and increase Connect Timeout as needed for
// device code flow.
string ConnectionString = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Device Code Flow; Encrypt=True;"
+ "Database=testdb; Connect Timeout=180;";
using (SqlConnection conn = new SqlConnection(ConnectionString)) {
conn.Open();
}
使用托管标识身份验证
建议使用 Azure 资源托管标识进行身份验证,以通过编程方式访问 SQL。 客户端应用程序可以使用系统分配或用户分配的资源托管标识,通过提供标识并用来获取访问令牌,从而使用 Microsoft Entra ID 对 SQL 进行身份验证。 此方法无需管理凭据和密码,并可简化访问管理。
托管标识分为两种类型:
- “系统分配的托管标识” 作为 Azure 资源(例如 SQL 托管实例或 逻辑服务器)的一部分而创建,并共享该资源的生命周期。 系统分配的标识只能与单个 Azure 资源相关联。
- 用户分配的托管标识是作为独立的 Azure 资源创建的。 可以将其分配给 Azure 服务的一个或多个实例。
有关托管标识的详细信息,请参阅关于 Azure 资源的托管标识。
自 Microsoft.Data.SqlClient 2.1.0 起,驱动程序支持通过托管标识获取访问令牌,实现对 Azure SQL 数据库、Azure Synapse Analytics 和 Azure SQL 托管实例进行身份验证。 若要使用此身份验证,请在连接字符串中指定 Active Directory Managed Identity
或 Active Directory MSI
,无需提供密码。 在此模式下,也不能设置 Credential
的 SqlConnection
属性。
对于用户分配的托管标识,在使用 Microsoft.Data.SqlClient v3.0 或更高版本时,必须提供托管标识的客户端 ID。 如果使用 Microsoft.Data.SqlClient v2.1,则必须提供托管标识的对象 ID。
下面的示例演示如何使用系统分配的托管标识进行 Active Directory Managed Identity
身份验证。
// For system-assigned managed identity
// Use your own values for Server and Database.
string ConnectionString1 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Managed Identity; Encrypt=True;"
+ "Database=testdb";
using (SqlConnection conn = new SqlConnection(ConnectionString1)) {
conn.Open();
}
string ConnectionString2 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory MSI; Encrypt=True; Database=testdb";
using (SqlConnection conn = new SqlConnection(ConnectionString2)) {
conn.Open();
}
下面的示例演示在使用 Microsoft.Data.SqlClient v3.0 及更高版本时,使用用户分配的托管标识进行的 Active Directory Managed Identity
身份验证。
// For user-assigned managed identity
// Use your own values for Server, Database, and User Id.
// With Microsoft.Data.SqlClient v3.0+
string ConnectionString1 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Managed Identity; Encrypt=True;"
+ "User Id=ClientIdOfManagedIdentity; Database=testdb";
using (SqlConnection conn = new SqlConnection(ConnectionString1)) {
conn.Open();
}
// With Microsoft.Data.SqlClient v3.0+
string ConnectionString2 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory MSI; Encrypt=True;"
+ "User Id=ClientIdOfManagedIdentity; Database=testdb";
using (SqlConnection conn = new SqlConnection(ConnectionString2)) {
conn.Open();
}
下面的示例演示在使用 Microsoft.Data.SqlClient v2.1 时,使用用户分配的托管标识进行的 Active Directory Managed Identity
身份验证。
// For user-assigned managed identity
// Use your own values for Server, Database, and User Id.
// With Microsoft.Data.SqlClient v2.1
string ConnectionString1 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Managed Identity; Encrypt=True;"
+ "User Id=ObjectIdOfManagedIdentity; Database=testdb";
using (SqlConnection conn = new SqlConnection(ConnectionString1)) {
conn.Open();
}
// With Microsoft.Data.SqlClient v2.1
string ConnectionString2 = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory MSI; Encrypt=True;"
+ "User Id=ObjectIdOfManagedIdentity; Database=testdb";
using (SqlConnection conn = new SqlConnection(ConnectionString2)) {
conn.Open();
}
使用默认身份验证
从版本 3.0 开始,此身份验证模式可扩大用户身份验证的可能性。 此模式可将登录解决方案扩展到客户端环境、Visual Studio Code、Visual Studio、Azure CLI 等。
在此身份验证模式下,驱动程序通过从 Azure 标识库传递“DefaultAzureCredential”来获取令牌和访问令牌。 此模式尝试使用这些凭据类型按顺序获取访问令牌。 根据使用的 Azure Identity 版本,凭据集会有所不同。 列表中记录了版本的具体差异。 有关 Azure Identity 版本特定行为,请参阅 Azure Identity API 文档。
重要
Active Directory 默认值 是简化不同环境之间的连接字符串差异的便捷选项。 但是,它可能会产生性能影响,因为它必须查找多个位置的身份验证信息。 如果在使用 Active Directory Default 时遇到连接速度缓慢,请尝试使用其他身份验证选项,这些选项专门适用于您环境中正在使用的身份验证方法。 对于具有严格服务级别响应时间的环境,不建议使用“Active Directory 默认值”。
-
环境凭证
- 使用客户端和机密、用户名和密码、以下环境变量中配置的详细信息来启用 Microsoft Entra ID 身份验证:AZURE_TENANT_ID、AZURE_CLIENT_ID、AZURE_CLIENT_SECRET、AZURE_CLIENT_CERTIFICATE_PATH、AZURE_USERNAME、AZURE_PASSWORD(更多详细信息)
-
WorkloadIdentityCredential
- 在 Kubernetes 和其他支持 Workload Identities 的主机上启用 Microsoft Entra Workload ID 身份验证。 有关详细信息,请参阅 Microsoft Entra 工作负载 ID。 从 Azure Identity 版本 1.10 和 Microsoft.Data.SqlClient 5.1.4 开始提供此功能。
-
ManagedIdentityCredential
- 使用分配给部署环境的托管标识尝试进行 Microsoft Entra ID 身份验证。 从“User Id”连接属性读取“用户分配的托管标识”的“客户端 ID” 。
-
SharedTokenCacheCredential
- 使用在 Microsoft 应用程序之间共享的本地缓存中的令牌进行身份验证。
-
VisualStudioCredential
- 使用 Visual Studio 中的数据启用 Microsoft Entra ID 身份验证
-
VisualStudioCodeCredential
- 使用 Visual Studio Code 中的数据启用 Microsoft Entra ID 身份验证。
-
AzurePowerShellCredential
- 使用 Azure PowerShell 启用通过 Microsoft Entra ID 进行身份验证。 从 Azure Identity 版本 1.6 和 Microsoft.Data.SqlClient 5.0 开始提供此功能。
-
AzureCliCredential
- 使用 Azure CLI 获取访问令牌来启用 Microsoft Entra ID 身份验证。
-
AzureDeveloperCliCredential
- 使用 Azure Developer CLI 获取访问令牌来启用 Microsoft Entra ID 身份验证。 从 Azure Identity 版本 1.10 和 Microsoft.Data.SqlClient 5.1.4 开始提供此功能。
注意
在Active Directory Default的驱动程序实现中,InteractiveBrowserCredential被禁用,而Active Directory Interactive是唯一可用于通过MFA/Interactive身份验证获取令牌的选项。
目前未提供其他自定义选项。
下面的示例演示如何使用“Active Directory 默认”身份验证。
// Use your own server, database
string ConnectionString = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Default; Encrypt=True; Database=testdb;";
using (SqlConnection conn = new SqlConnection(ConnectionString)) {
conn.Open();
}
使用工作负载标识身份验证
从版本 5.2 开始,与托管标识一样,workload identity 身份验证模式使用连接字符串中的 User ID
参数值作为其客户端 ID(如指定)。 但与托管标识不同,WorkloadIdentityCredentialOptions 的默认值来自环境变量:AZURE_TENANT_ID、AZURE_CLIENT_ID 及 AZURE_FEDERATED_TOKEN_FILE。 但是,只有客户端 ID 可以通过连接字符串进行重写。
下面的示例演示在使用 Microsoft.Data.SqlClient v5.2 及更高版本时,使用用户分配的托管标识进行的 Active Directory Workload Identity
身份验证。
// Use your own values for Server, Database, and User Id.
// With Microsoft.Data.SqlClient v5.2+
string ConnectionString = @"Server=demo.database.windows.net;"
+ "Authentication=Active Directory Workload Identity; Encrypt=True;"
+ "User Id=ClientIdOfManagedIdentity; Database=testdb";
using (SqlConnection conn = new SqlConnection(ConnectionString)) {
conn.Open();
}
自定义 Microsoft Entra 身份验证
除了使用驱动程序中内置的 Microsoft Entra 身份验证外,Microsoft.Data.SqlClient 2.1.0 和更高版本还为应用程序提供了自定义 Microsoft Entra 身份验证的选项。 自定义基于 ActiveDirectoryAuthenticationProvider
类,该类派生自 SqlAuthenticationProvider
抽象类。
在 Microsoft Entra 身份验证期间,客户端应用程序可以通过以下任一方法定义其自己的 ActiveDirectoryAuthenticationProvider
类:
- 使用自定义的回调方法。
- 通过 SqlClient 驱动程序将应用程序客户端 ID 传递到 MSAL 库,用于获取访问令牌。
下面的示例演示如何在使用 Active Directory Device Code Flow
身份验证时使用自定义回调。
using System;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using Microsoft.Data.SqlClient;
namespace CustomAuthenticationProviderExamples
{
public class Program
{
public static void Main()
{
SqlAuthenticationProvider authProvider = new ActiveDirectoryAuthenticationProvider(CustomDeviceFlowCallback);
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider);
using (SqlConnection sqlConnection = new SqlConnection("Server=<myserver>.database.windows.net;Authentication=Active Directory Device Code Flow;Database=<db>;"))
{
sqlConnection.Open();
Console.WriteLine("Connected successfully!");
}
}
private static Task CustomDeviceFlowCallback(DeviceCodeResult result)
{
// Provide custom logic to process result information and read device code.
Console.WriteLine(result.Message);
return Task.FromResult(0);
}
}
}
使用自定义的 ActiveDirectoryAuthenticationProvider
类时,如果正在使用支持的 Microsoft Entra 身份验证模式,则可以将用户定义的应用程序客户端 ID 传递到 SqlClient。 支持的 Microsoft Entra 身份验证模式包括 Active Directory Password
、Active Directory Integrated
、Active Directory Interactive
、Active Directory Service Principal
及 Active Directory Device Code Flow
。
应用程序客户端 ID 还可通过 SqlAuthenticationProviderConfigurationSection
或 SqlClientAuthenticationProviderConfigurationSection
进行配置。 配置属性 applicationClientId
适用于 .NET Framework 4.6 + 和 .NET Core 2.1 +。
以下代码片段是在使用 ActiveDirectoryAuthenticationProvider
身份验证时使用自定义的 Active Directory Interactive
类和用户定义的应用程序客户端 ID 的示例。
using System;
using Microsoft.Data.SqlClient;
namespace CustomAuthenticationProviderExamples
{
public class Program
{
public static void Main()
{
// Supported for all authentication modes supported by ActiveDirectoryAuthenticationProvider
ActiveDirectoryAuthenticationProvider provider = new ActiveDirectoryAuthenticationProvider("<application_client_id>");
if (provider.IsSupported(SqlAuthenticationMethod.ActiveDirectoryInteractive))
{
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, provider);
}
using (SqlConnection sqlConnection = new SqlConnection("Server=<myserver>.database.windows.net;Authentication=Active Directory Interactive;Database=<db>;"))
{
sqlConnection.Open();
Console.WriteLine("Connected successfully!");
}
}
}
}
以下示例演示如何通过配置节设置应用程序客户端 ID。
<configuration>
<configSections>
<section name="SqlClientAuthenticationProviders"
type="Microsoft.Data.SqlClient.SqlClientAuthenticationProviderConfigurationSection, Microsoft.Data.SqlClient" />
</configSections>
<SqlClientAuthenticationProviders applicationClientId ="<GUID>" />
</configuration>
<!--or-->
<configuration>
<configSections>
<section name="SqlAuthenticationProviders"
type="Microsoft.Data.SqlClient.SqlAuthenticationProviderConfigurationSection, Microsoft.Data.SqlClient" />
</configSections>
<SqlAuthenticationProviders applicationClientId ="<GUID>" />
</configuration>
使用 AccessTokenCallback
在版本 5.2 及更高版本中,SqlConnection 上将提供一个新的 AccessTokenCallback 属性。 使用该 AccessTokenCallback
属性可定义一个自定义函数,该函数返回给定传入参数的访问令牌。 使用回调比使用 AccessToken 属性更好,因为它允许在连接池中刷新访问令牌。 使用 AccessToken
属性时,无法在打开连接后更新令牌。 也没有通过属性提供的关联到期日期。 令牌过期后,新的连接请求会失败,并出现服务器身份验证错误,并且必须手动清除使用该令牌的池。
重要
对于相同输入参数,AccessTokenCallback
必须返回相同安全性上下文的访问令牌。 如果安全上下文不同,则可能会为连接请求返回具有错误安全上下文的池连接。
注意
AccessTokenCallback
是用于标识连接池的键的一部分。 避免为每次创建 SqlConnection 创建新的函数回调,因为这会导致每次都生成一个新池。 对于希望考虑池化的连接,请引用函数的同一实例。 连接池键包括传递给回调的参数,以便合理地对连接池进行分区。
以下代码片段是使用 AccessTokenCallback
中的 属性的示例。
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
using Azure.Identity;
using Microsoft.Data.SqlClient;
class Program
{
static void Main()
{
OpenSqlConnection();
Console.ReadLine();
}
const string defaultScopeSuffix = "/.default";
// Reuse credential objects to take advantage of underlying token caches.
private static ConcurrentDictionary<string, DefaultAzureCredential> credentials = new ConcurrentDictionary<string, DefaultAzureCredential>();
// Use a shared callback function for connections that should be in the same connection pool.
private static Func<SqlAuthenticationParameters, CancellationToken, Task<SqlAuthenticationToken>> myAccessTokenCallback =
async (authParams, cancellationToken) =>
{
string scope = authParams.Resource.EndsWith(defaultScopeSuffix)
? authParams.Resource
: $"{authParams.Resource}{defaultScopeSuffix}";
DefaultAzureCredentialOptions options = new DefaultAzureCredentialOptions();
options.ManagedIdentityClientId = authParams.UserId;
// Reuse the same credential object if we are using the same MI Client Id.
AccessToken token = await credentials.GetOrAdd(authParams.UserId, new DefaultAzureCredential(options)).GetTokenAsync(
new TokenRequestContext(new string[] { scope }),
cancellationToken);
return new SqlAuthenticationToken(token.Token, token.ExpiresOn);
};
private static void OpenSqlConnection()
{
// (Optional) Pass a User-Assigned Managed Identity Client ID.
// This will ensure different MI Client IDs are in different connection pools.
string connectionString = "Server=myServer.database.windows.net;Encrypt=Mandatory;UserId=<ManagedIdentitityClientId>;";
using (SqlConnection connection = new SqlConnection(connectionString)
{
// The callback function is part of the connection pool key. Using a static callback function
// ensures connections will not create a new pool per connection just for the callback.
AccessTokenCallback = myAccessTokenCallback
})
{
connection.Open();
Console.WriteLine("ServerVersion: {0}", connection.ServerVersion);
Console.WriteLine("State: {0}", connection.State);
}
}
}
支持自定义 SQL 身份验证提供程序
获得更多灵活性后,客户端应用程序还可以使用自己的提供程序进行 Microsoft Entra ID 身份验证,而不是使用 ActiveDirectoryAuthenticationProvider
类。 自定义身份验证提供程序需要是具有重写方法的 SqlAuthenticationProvider
的子类。 然后,它必须注册自定义提供程序,替代一个或多个现有的 Active Directory*
身份验证方法。
重要
身份验证提供程序必须为相同的输入参数返回相同安全上下文的访问令牌。 如果安全上下文不同,则可能会为连接请求返回具有错误安全上下文的池连接。
下面的示例演示如何使用新的身份验证提供程序进行 Active Directory Device Code Flow
身份验证。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
using Microsoft.Identity.Client;
namespace CustomAuthenticationProviderExamples
{
/// <summary>
/// Example demonstrating creating a custom device code flow authentication provider and attaching it to the driver.
/// This is helpful for applications that wish to override the Callback for the Device Code Result implemented by the SqlClient driver.
/// </summary>
public class CustomDeviceCodeFlowAzureAuthenticationProvider : SqlAuthenticationProvider
{
private const string ClientId = "my-client-id";
private const string ClientName = "My Application Name";
private const string DefaultScopeSuffix = "/.default";
// Maintain a copy of the PublicClientApplication object to cache the underlying access tokens it provides
private static IPublicClientApplication pcApplication;
public override async Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters)
{
string[] scopes = [ parameters.Resource.EndsWith(DefaultScopeSuffix) ? parameters.Resource : parameters.Resource + DefaultScopeSuffix ];
IPublicClientApplication app = pcApplication;
if (app == null)
{
pcApplication = app = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(parameters.Authority)
.WithClientName(ClientName)
.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
.Build();
}
AuthenticationResult result;
using CancellationTokenSource connectionTimeoutCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(parameters.ConnectionTimeout));
try
{
IEnumerable<IAccount> accounts = await app.GetAccountsAsync();
result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync(connectionTimeoutCancellation.Token);
}
catch (MsalUiRequiredException)
{
result = await app.AcquireTokenWithDeviceCode(scopes, deviceCodeResult => CustomDeviceFlowCallback(deviceCodeResult))
.ExecuteAsync(connectionTimeoutCancellation.Token);
}
return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn);
}
public override bool IsSupported(SqlAuthenticationMethod authenticationMethod)
=> authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow);
private static Task CustomDeviceFlowCallback(DeviceCodeResult result)
{
Console.WriteLine(result.Message);
return Task.CompletedTask;
}
}
public class Program
{
public static void Main()
{
// Register our custom authentication provider class to override Active Directory Device Code Flow
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, new CustomDeviceCodeFlowAzureAuthenticationProvider());
using (SqlConnection sqlConnection = new SqlConnection("Server=<myserver>.database.windows.net;Authentication=Active Directory Device Code Flow;Database=<db>;"))
{
sqlConnection.Open();
Console.WriteLine("Connected successfully!");
}
}
}
}
除了改进 Active Directory Interactive
身份验证体验之外,Microsoft.Data.SqlClient 2.1.0 和更高版本还为客户端应用程序提供了以下 API,用于自定义交互式身份验证和设备代码流身份验证。
public class ActiveDirectoryAuthenticationProvider
{
// For .NET Framework targeted applications only
// Sets a reference to the current System.Windows.Forms.IWin32Window that triggers
// the browser to be shown.
// Used to center the browser pop-up onto this window.
public void SetIWin32WindowFunc(Func<IWin32Window> iWin32WindowFunc);
// For .NET Standard targeted applications only
// Sets a reference to the ViewController (if using .NET for iOS), Activity
// (if using .NET for Android) IWin32Window, or IntPtr (if using .NET Framework).
// Used for invoking the browser for Active Directory Interactive authentication.
public void SetParentActivityOrWindowFunc(Func<object> parentActivityOrWindowFunc);
// For .NET Framework, .NET Core, and .NET Standard targeted applications
// Sets a callback method that's invoked with a custom web UI instance that lets
// the user sign in with Azure AD, present consent if needed, and get back the
// authorization code.
// Applicable when working with Active Directory Interactive authentication.
public void SetAcquireAuthorizationCodeAsyncCallback(Func<Uri, Uri, CancellationToken,
Task<Uri>> acquireAuthorizationCodeAsyncCallback);
// For .NET Framework, .NET Core, and .NET Standard targeted applications
// Clears cached user tokens from the token provider.
public static void ClearUserTokenCache();
}