使用 mssql-django 的 Microsoft Entra 驗證

本文說明如何利用mssql-django後端設定 Microsoft Entra 為 Django 應用程式進行認證。 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

驗證方法

透過新增或編輯 DATABASES Django 專案 settings.py 檔案中的設定來設定每個方法。 本文範例展示了整個 DATABASES["default"] 區塊以便清楚;將相關金鑰複製到你現有的設定中。

mssql-django 支援以兩種方式使用 Microsoft Entra 驗證:

  • ODBC 驅動程式認證透過 OPTIONS["extra_params"]。 後端會將此字串附加到 ODBC 連接字串 上,保持不變,因此可用Authentication=值來自已安裝的 Microsoft ODBC 驅動程式 for SQL Server,而非mssql-django自身。
  • 透過 TOKEN 設定進行程式化存取權杖認證。 後端會傳送 TOKEN 給 ODBC 驅動程式,以 SQL_COPT_SS_ACCESS_TOKEN的方式繞過 ODBC Authentication= 關鍵字。

認證方法一覽

方法 配置方式 最適合用於
存取憑證 TOKEN 開發、短期執行的指令碼,或具有自訂權杖重新整理功能的應用程式
ActiveDirectoryMsi extra_params 裝載於 Azure 的生產環境應用程式(系統指派和使用者指派的受控識別)
ActiveDirectoryServicePrincipal USERPASSWORDextra_params 當無法使用受控識別時的應用程式註冊
ActiveDirectoryIntegrated extra_params 網域連結使用者上下文
ActiveDirectoryInteractive USERextra_params 使用者多重驗證登入(Windows)
ActiveDirectoryDefault extra_params 本地開發與應用,應該使用 ODBC 驅動程式預設的 Microsoft Entra 憑證鏈
ActiveDirectoryPassword USERPASSWORDextra_params 僅限最後手段遺留情境(已棄用)

Note

mssql-django 1.7.3 及更新版本會接受 Authentication=ActiveDirectoryDefaultOPTIONS["extra_params"],前提是已安裝的 Microsoft ODBC Driver for SQL Server 支援該模式。 如果你需要明確控制代幣獲取和刷新行為,請使用 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 足夠了。

Note

FROM EXTERNAL PROVIDER需要 SQL 伺服器呼叫 Microsoft Graph 來解析主體名稱。 如果伺服器設定為僅限 Microsoft Entra 驗證,或因其他原因無法連線到 Graph,則該陳述式會失敗,並顯示 Msg 33130Principal '<name>' could not be found...)。 改為手動建立使用者,提供明確的 SID:

CREATE USER [<identity-name>] WITH SID = 0x<sid-hex>, TYPE = E;

對於受管理身份或服務主體,應從該身份的 應用程式(用戶端)ID(而非物件ID)推導SID。 Azure SQL 會用應用程式 ID 來管理服務主體和受管理身份,而物件 ID 只用於一般 Entra 使用者。 將 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 錯誤,請授予該身份在「始終加密」情境下額外存取權限:

GRANT VIEW ANY COLUMN MASTER KEY DEFINITION TO [<identity-name>];
GRANT VIEW ANY COLUMN ENCRYPTION KEY DEFINITION TO [<identity-name>];

管理身份驗證(ActiveDirectoryMsi

當你的 Django 應用程式在 Azure 服務上運行時,請使用管理身份,例如 Azure App 服務、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 App 服務 或 Azure Container Instance 的客戶端 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 Key Vault 這類秘密管理器,在執行時提供憑證。

整合驗證(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": "<user@email.com>",
        "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 憑證類別,包括 DefaultAzureCredentialManagedIdentityCredentialClientSecretCredential

settings.py 中取得的存取權杖只會在處理程序啟動時評估一次,且通常會在 60 到 90 分鐘後失效。 如果你的 Django 程序存活時間超過標記壽命,你必須在應用程式碼中刷新標記。 對於大多數長時間運行的生產應用程式,可以使用 ODBC 驅動程式模式自動刷新標記,例如 ActiveDirectoryMsiActiveDirectoryServicePrincipal或 。

密碼驗證(ActiveDirectoryPassword已棄用)

Important

ActiveDirectoryPassword 驗證選項(Microsoft Entra ID 密碼驗證)在 Microsoft SQL 驅動程式中已被棄用。 這種高風險的認證流程與強制的 Microsoft Entra 多重驗證(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": "<user@email.com>",
        "PASSWORD": "<your-password>",
        "HOST": "<your-server>.database.windows.net",
        "PORT": "1433",
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "extra_params": "Authentication=ActiveDirectoryPassword",
        },
    },
}