本文介绍如何使用mssql-django后端为 Django 应用程序配置Microsoft Entra身份验证。 Microsoft Entra身份验证无需在应用程序配置中存储密码。
先决条件
-
Microsoft ODBC Driver 18 for SQL Server(建议)。 Microsoft ODBC Driver 18 for SQL Server 支持本文中的所有身份验证模式。
ActiveDirectoryInteractive仅限 Windows,不论驱动程序版本如何。 如果必须使用 ODBC 驱动程序 17,请参阅 ODBC 身份验证参考,了解各模式所需的最低 17.x 版本。 - 使用访问令牌进行身份验证:
pip install azure-identity
身份验证方法
通过在 Django 项目的DATABASES文件中添加或编辑settings.py设置来配置每个方法。 本文中的示例演示完整 DATABASES["default"] 块,以便清楚起见,请将相关密钥复制到现有配置中。
mssql-django通过两种方式支持Microsoft Entra身份验证:
- 通过
OPTIONS["extra_params"]进行 ODBC 驱动程序身份验证。 后端将此字符串原样附加到 ODBC 连接字符串后面,因此,可用的Authentication=值来自已安装的 Microsoft ODBC Driver for SQL Server,而不是来自mssql-django本身。 - 通过
TOKEN设置以编程方式使用访问令牌进行身份验证。 后端将TOKEN以SQL_COPT_SS_ACCESS_TOKEN的形式传递给 ODBC 驱动程序,从而绕过 ODBCAuthentication=关键字。
身份验证方法一目了然
| 方法 | 使用以下项配置 | 最适用于 |
|---|---|---|
| 访问令牌 | TOKEN |
开发、短期运行的脚本,或具有自定义令牌刷新功能的应用 |
ActiveDirectoryMsi |
extra_params |
托管在 Azure 上的生产环境应用(系统分配的托管标识和用户分配的托管标识) |
ActiveDirectoryServicePrincipal |
USER、PASSWORD、extra_params |
当托管标识不可用时的应用注册 |
ActiveDirectoryIntegrated |
extra_params |
已加入域的用户上下文 |
ActiveDirectoryInteractive |
USER、extra_params |
使用多重身份验证的用户登录(Windows) |
ActiveDirectoryDefault |
extra_params |
应使用 ODBC 驱动程序默认 Microsoft Entra 凭据链的本地开发和应用程序 |
ActiveDirectoryPassword |
USER、PASSWORD、extra_params |
仅用于万不得已时的旧版场景(已弃用) |
注释
mssql-django 当已安装的 Microsoft ODBC Driver for SQL Server 支持该模式时,1.7.3 及更高版本接受 Authentication=ActiveDirectoryDefault 到 OPTIONS["extra_params"]。 如果需要显式控制令牌获取和刷新行为,请在类中使用 TOKEN 模式 azure.identity.DefaultAzureCredential 。
在 Azure SQL 中授予标识访问权限
对于托管标识或服务主体身份验证,请创建数据库用户,并仅授予应用程序所需的角色:
CREATE USER [<identity-name>] FOR EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [<identity-name>];
ALTER ROLE db_datawriter ADD MEMBER [<identity-name>];
ALTER ROLE db_ddladmin ADD MEMBER [<identity-name>];
仅当应用程序运行迁移时,才需要 db_ddladmin 固定数据库角色。 对于只读工作负荷, db_datareader 已足够。
注释
FROM EXTERNAL PROVIDER要求 SQL Server 调用Microsoft Graph来解析主体名称。 如果服务器配置为仅Microsoft Entra身份验证,否则无法访问 Graph,则语句将失败并出现 Msg 33130 (Principal '<name>' could not be found...)。 请改为通过提供显式 SID 手动创建用户:
CREATE USER [<identity-name>] WITH SID = 0x<sid-hex>, TYPE = E;
对于托管标识或服务主体,请根据该标识的 应用程序(客户端)ID 派生 SID,而不要根据其对象 ID 派生。 Azure SQL将应用程序 ID 用于服务主体和托管标识,并且仅对常规 Entra 用户使用对象 ID。 通过将前三个由短划线分隔的组按字节逐一反转,并保持最后两个组不变,来转换 GUID。 例如,应用程序 ID 619a4449-b4aa-4383-a2a9-7c365106c5e7 变为 SID 0x49449A61AAB48343A2A97C365106C5E7。 在 PowerShell 中:
$b = ([Guid]"<app-id>").ToByteArray()
"0x" + (($b | ForEach-Object { $_.ToString('X2') }) -join '')
如果误用了对象 ID,连接虽然能够成功获取令牌,但 Azure SQL 会返回 Login failed for user '<token-identified principal>',因为没有任何数据库主体与令牌中的 appid 声明相匹配。
如果出现 VIEW ANY COLUMN MASTER KEY DEFINITION permission denied 错误,请为 Always Encrypted 场景授予该标识身份额外的访问权限:
GRANT VIEW ANY COLUMN MASTER KEY DEFINITION TO [<identity-name>];
GRANT VIEW ANY COLUMN ENCRYPTION KEY DEFINITION TO [<identity-name>];
托管标识身份验证(ActiveDirectoryMsi)
当 Django 应用在Azure服务(例如Azure 应用服务、Azure 容器应用或Azure 虚拟机)上运行时,请使用托管标识。 建议对生产环境使用此方法,因为 ODBC 驱动程序会自动获取和刷新令牌。
系统分配的托管标识:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>.database.windows.net",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "Authentication=ActiveDirectoryMsi",
},
},
}
用户分配的托管标识:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>.database.windows.net",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": (
"Authentication=ActiveDirectoryMsi;"
"UID=<managed-identity-client-id-or-object-id>"
),
},
},
}
ActiveDirectoryMsi 是系统分配的托管标识(SAMI)和用户分配的托管标识(UAMI)的 ODBC 模式。 对于 UAMI,ODBC 驱动程序使用 UID 来标识托管标识:对于 Azure 应用服务 或 Azure 容器实例,请使用客户端 ID;否则,请使用对象 ID。 把 UID 放在 extra_params 里面,因为 extra_params 会直接传递给 ODBC 驱动程序。
如果使用托管标识,请手动创建测试数据库,并在运行单元测试时传递 --keepdb 参数。
服务主体身份验证(ActiveDirectoryServicePrincipal)
当应用在没有用户上下文且无法使用托管标识的情况下运行时,请使用 Microsoft Entra 应用注册(服务主体)。
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<application-client-id>",
"PASSWORD": "<client-secret>",
"HOST": "<your-server>.database.windows.net",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "Authentication=ActiveDirectoryServicePrincipal",
},
},
}
不要在 settings.py 中硬编码客户端机密。 使用环境变量或机密管理器(例如Azure 密钥保管库)在运行时提供凭据。
集成身份验证 (ActiveDirectoryIntegrated)
当 Django 进程在已加入域的用户上下文中运行,并且希望 ODBC 驱动程序使用该 Windows 或 Kerberos 身份进行 Microsoft Entra 身份验证时,请使用集成身份验证。
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>.database.windows.net",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "Authentication=ActiveDirectoryIntegrated",
},
},
}
ODBC 身份验证参考文档记录了这种模式在 Windows 上的用法,以及在 Linux 或 macOS 上使用 ODBC Driver 17.6 及更高版本时在联合环境中的用法。
交互式身份验证 (ActiveDirectoryInteractive)
如果希望驱动程序提示输入凭据并处理多重身份验证,请使用本地用户登录的交互式身份验证。
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<[email protected]>",
"HOST": "<your-server>.database.windows.net",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "Authentication=ActiveDirectoryInteractive",
},
},
}
主要的 ODBC 身份验证参考文档将 ActiveDirectoryInteractive 标注为仅限 Windows。 如果打算在另一个平台上使用它,请先使用确切的驱动程序版本验证行为。
默认凭据链身份验证 (ActiveDirectoryDefault)
如果希望 ODBC 驱动程序应用其默认Microsoft Entra凭据链,请使用此模式。
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>.database.windows.net",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "Authentication=ActiveDirectoryDefault",
},
},
}
mssql-django 1.7.3 及更高版本将此模式传递到 ODBC 驱动程序。 如果需要显式控制凭据源或令牌刷新行为,请使用 访问令牌身份验证。
访问令牌身份验证 (TOKEN)
当你希望你的 Python 代码自行获取 Microsoft Entra 令牌时,请使用 TOKEN。
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
token = credential.get_token("https://database.windows.net/.default").token
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>.database.windows.net",
"PORT": "1433",
"TOKEN": token,
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
},
}
此路径适用于任何Python凭据类,包括DefaultAzureCredential,ManagedIdentityCredential和ClientSecretCredential。
在 settings.py 中获取的访问令牌只会在进程启动时评估一次,通常会在 60 到 90 分钟后过期。 如果 Django 进程保持活动时间超过令牌生存期,则必须在应用程序代码中刷新令牌。 对于大多数长时间运行的生产应用,请使用自动刷新令牌的 ODBC 驱动程序模式,例如 ActiveDirectoryMsi 或 ActiveDirectoryServicePrincipal。
密码身份验证(ActiveDirectoryPassword已弃用)
Important
Microsoft SQL 驱动程序中弃用 ActiveDirectoryPassword 身份验证选项(Microsoft Entra ID密码身份验证)。 此高风险身份验证流与强制Microsoft Entra多重身份验证(MFA)不兼容,在强制实施 MFA 的租户中可能不起作用。 计划迁移到其他Microsoft Entra身份验证方法。
Microsoft Entra ID密码身份验证基于 OAuth 2.0 资源所有者密码凭据(ROPC)授予,允许应用程序直接处理其密码来登录用户。
Microsoft建议不要使用 ROPC 流,因为它与 MFA 不兼容。 在大多数情况下,可以使用我们建议的更安全的替代方案。 此流要求在应用程序中高度信任,并且存在在其他流中不存在的风险。 仅当更安全的流不可行时,才使用此流。 Microsoft正远离此高风险身份验证流,以保护用户免受恶意攻击。 有关详细信息,请参阅 规划 Azure 的强制多重身份验证。
如果登录时有用户在场,请使用 ActiveDirectoryInteractive 或 ActiveDirectoryIntegrated 身份验证,以便审核跟踪记录归属于已登录用户,并使条件访问策略生效。
对于无人值守的服务到服务场景,请遵循Microsoft Entra 服务帐户指南:
- 如果应用程序在Azure基础结构上运行,请使用 ActiveDirectoryMSI(或某些驱动程序中的 ActiveDirectoryManagedIdentity)。 托管标识消除了维护和轮换机密和证书的开销。
- 如果托管标识不可用(例如,应用程序在 Azure 外部运行),请使用 ActiveDirectoryServicePrincipal。 在驱动程序支持的情况下,应优先使用客户端证书,而非客户端机密。 使用证书时,私钥会保留在客户端上,并且仅将签名断言发送到Microsoft Entra对客户端进行身份验证。 如果密钥存储在硬件(如 TPM 或 HSM)中,或者被标记为不可导出,就无法像客户端密码那样以字符串形式将其复制出来。
- 不要使用Microsoft Entra用户帐户作为服务帐户。
如果确实必须在遗留场景中使用它,请显式地进行配置:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<[email protected]>",
"PASSWORD": "<your-password>",
"HOST": "<your-server>.database.windows.net",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "Authentication=ActiveDirectoryPassword",
},
},
}