如何使用 Active Directory 登录和多重身份验证 (MFA) 连接到数据库

use*_*er1 8 c# sql-server authentication azure azure-sql-database

我已经配置了我的 Azure SQL Server,以便我成为服务器管理员,我的帐户也启用了 MFA。我试图遵循此文档,但它没有提及任何有关具有 MFA 的 Active Directory 的内容。

我可以使用我的帐户和 MFA 使用 SQL Management studio 正常登录服务器

最初我尝试过(基于新的SqlAuthenticationMethod Enum):

SqlConnection con = new SqlConnection("Server=tcp:myapp.database.windows.net;Database=CustomerDB;Authentication=Active Directory Interactive;Encrypt=True;UID=User@User.co.uk"))
Run Code Online (Sandbox Code Playgroud)

错误:

“找不到‘ActiveDirectoryInteractive’的身份验证提供程序。”

然后我看到了有关通过 Azure 应用程序访问 SQL 的信息,但这不是我想要做的。

这个SO问题讨论了在没有提供者的情况下进行连接并Driver在连接字符串中设置

SqlConnection con = new SqlConnection("DRIVER={ODBC Driver 17 for SQL Server};Server=tcp:myapp.database.windows.net;Database=CustomerDB;Authentication=Active Directory Interactive;Encrypt=True;UID=User@User.co.uk"))
Run Code Online (Sandbox Code Playgroud)

但我收到错误:

“不支持关键字:‘驱动程序’。”

是否有办法编写一个连接字符串,以便在尝试连接时弹出 Microsoft 身份验证框以引导用户完成多因素身份验证?

Alb*_*llo 8

要使用 Azure AD 身份验证,您的 C# 程序必须注册为 Azure AD 应用程序。完成应用程序注册会生成并显示应用程序 ID。您的程序必须包含此 ID 才能连接。要注册应用程序并设置必要的权限,请转到 Azure 门户,选择 Azure Active Directory > 应用程序注册 > 新注册。

在此输入图像描述

创建应用程序注册后,将生成并显示应用程序 ID 值。

在此输入图像描述

选择 API 权限 > 添加权限。

在此输入图像描述

选择我的组织使用的 API > 在搜索中键入 Azure SQL 数据库 > 然后选择 Azure SQL 数据库。

在此输入图像描述

选择委派权限 > user_impersonation > 添加权限。

在此输入图像描述

您似乎已经为 Azure SQL 数据库设置了 Azure AD 管理员。

您还可以使用 SQL 创建用户命令将用户添加到数据库。一个例子是 CREATE USER [] FROM EXTERNAL PROVIDER。欲了解更多信息,请参见此处

下面是 C# 的示例。

using System;

// Reference to Azure AD authentication assembly
using Microsoft.IdentityModel.Clients.ActiveDirectory;

using DA = System.Data;
using SC = System.Data.SqlClient;
using AD = Microsoft.IdentityModel.Clients.ActiveDirectory;
using TX = System.Text;
using TT = System.Threading.Tasks;

namespace ADInteractive5
{
    class Program
    {
        // ASSIGN YOUR VALUES TO THESE STATIC FIELDS !!
        static public string Az_SQLDB_svrName = "<Your SQL DB server>";
        static public string AzureAD_UserID = "<Your User ID>";
        static public string Initial_DatabaseName = "<Your Database>";
        // Some scenarios do not need values for the following two fields:
        static public readonly string ClientApplicationID = "<Your App ID>";
        static public readonly Uri RedirectUri = new Uri("<Your URI>");

        public static void Main(string[] args)
        {
            var provider = new ActiveDirectoryAuthProvider();

            SC.SqlAuthenticationProvider.SetProvider(
                SC.SqlAuthenticationMethod.ActiveDirectoryInteractive,
                //SC.SqlAuthenticationMethod.ActiveDirectoryIntegrated,  // Alternatives.
                //SC.SqlAuthenticationMethod.ActiveDirectoryPassword,
                provider);

            Program.Connection();
        }

        public static void Connection()
        {
            SC.SqlConnectionStringBuilder builder = new SC.SqlConnectionStringBuilder();

            // Program._  static values that you set earlier.
            builder["Data Source"] = Program.Az_SQLDB_svrName;
            builder.UserID = Program.AzureAD_UserID;
            builder["Initial Catalog"] = Program.Initial_DatabaseName;

            // This "Password" is not used with .ActiveDirectoryInteractive.
            //builder["Password"] = "<YOUR PASSWORD HERE>";

            builder["Connect Timeout"] = 15;
            builder["TrustServerCertificate"] = true;
            builder.Pooling = false;

            // Assigned enum value must match the enum given to .SetProvider().
            builder.Authentication = SC.SqlAuthenticationMethod.ActiveDirectoryInteractive;
            SC.SqlConnection sqlConnection = new SC.SqlConnection(builder.ConnectionString);

            SC.SqlCommand cmd = new SC.SqlCommand(
                "SELECT '******** MY QUERY RAN SUCCESSFULLY!! ********';",
                sqlConnection);

            try
            {
                sqlConnection.Open();
                if (sqlConnection.State == DA.ConnectionState.Open)
                {
                    var rdr = cmd.ExecuteReader();
                    var msg = new TX.StringBuilder();
                    while (rdr.Read())
                    {
                        msg.AppendLine(rdr.GetString(0));
                    }
                    Console.WriteLine(msg.ToString());
                    Console.WriteLine(":Success");
                }
                else
                {
                    Console.WriteLine(":Failed");
                }
                sqlConnection.Close();
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Connection failed with the following exception...");
                Console.WriteLine(ex.ToString());
                Console.ResetColor();
            }
        }
    } // EOClass Program.

    /// <summary>
    /// SqlAuthenticationProvider - Is a public class that defines 3 different Azure AD
    /// authentication methods.  The methods are supported in the new .NET 4.7.2.
    ///  . 
    /// 1. Interactive,  2. Integrated,  3. Password
    ///  . 
    /// All 3 authentication methods are based on the Azure
    /// Active Directory Authentication Library (ADAL) managed library.
    /// </summary>
    public class ActiveDirectoryAuthProvider : SC.SqlAuthenticationProvider
    {
        // Program._ more static values that you set!
        private readonly string _clientId = Program.ClientApplicationID;
        private readonly Uri _redirectUri = Program.RedirectUri;

        public override async TT.Task<SC.SqlAuthenticationToken>
            AcquireTokenAsync(SC.SqlAuthenticationParameters parameters)
        {
            AD.AuthenticationContext authContext =
                new AD.AuthenticationContext(parameters.Authority);
            authContext.CorrelationId = parameters.ConnectionId;
            AD.AuthenticationResult result;

            switch (parameters.AuthenticationMethod)
            {
                case SC.SqlAuthenticationMethod.ActiveDirectoryInteractive:
                    Console.WriteLine("In method 'AcquireTokenAsync', case_0 == '.ActiveDirectoryInteractive'.");

                    result = await authContext.AcquireTokenAsync(
                        parameters.Resource,  // "https://database.windows.net/"
                        _clientId,
                        _redirectUri,
                        new AD.PlatformParameters(AD.PromptBehavior.Auto),
                        new AD.UserIdentifier(
                            parameters.UserId,
                            AD.UserIdentifierType.RequiredDisplayableId));
                    break;

                case SC.SqlAuthenticationMethod.ActiveDirectoryIntegrated:
                    Console.WriteLine("In method 'AcquireTokenAsync', case_1 == '.ActiveDirectoryIntegrated'.");

                    result = await authContext.AcquireTokenAsync(
                        parameters.Resource,
                        _clientId,
                        new AD.UserCredential());
                    break;

                case SC.SqlAuthenticationMethod.ActiveDirectoryPassword:
                    Console.WriteLine("In method 'AcquireTokenAsync', case_2 == '.ActiveDirectoryPassword'.");

                    result = await authContext.AcquireTokenAsync(
                        parameters.Resource,
                        _clientId,
                        new AD.UserPasswordCredential(
                            parameters.UserId,
                            parameters.Password));
                    break;

                default: throw new InvalidOperationException();
            }
            return new SC.SqlAuthenticationToken(result.AccessToken, result.ExpiresOn);
        }

        public override bool IsSupported(SC.SqlAuthenticationMethod authenticationMethod)
        {
            return authenticationMethod == SC.SqlAuthenticationMethod.ActiveDirectoryIntegrated
                || authenticationMethod == SC.SqlAuthenticationMethod.ActiveDirectoryInteractive
                || authenticationMethod == SC.SqlAuthenticationMethod.ActiveDirectoryPassword;
        }
    } // EOClass ActiveDirectoryAuthProvider.
} // EONamespace.  End of entire program source code.
Run Code Online (Sandbox Code Playgroud)

上面的示例依赖于 Microsoft.IdentityModel.Clients.ActiveDirectory DLL 程序集。

若要安装此包,请在 Visual Studio 中选择“项目”>“管理 NuGet 包”。搜索并安装 Microsoft.IdentityModel.Clients.ActiveDirectory。

从 .NET Framework 版本 4.7.2 开始,枚举 SqlAuthenticationMethod 具有新值:ActiveDirectoryInteractive。