Microsoft。Identity.Web 支援憑證式認證,作為機密用戶端應用程式中用戶端秘密的安全替代方案。 憑證使用非對稱密碼學,因此只有私鑰持有者能進行認證。
在本文中,你將從各種來源設定憑證憑證,註冊到你的應用程式,並在生產環境中加以管理。
為什麼要使用憑證?
| 因素 | 用戶端密碼 | 證書 |
|---|---|---|
| 安全性 | 共享密鑰(對稱) | 非對稱金鑰對 |
| 旋轉 | 需要重新部署應用程式或更改設定 | 可透過 金鑰保存庫 自動化 |
| 暴露風險 | 設定中的秘密可能會被洩漏 | 私鑰會保存在安全儲存中 |
| 合規性 | 可能不符合企業政策 | 符合大多數企業安全需求 |
| 推薦用於 | 開發與原型製作 | 生產工作負載 |
這很重要
Microsoft 建議在生產應用程式中使用憑證而非用戶端秘密。 為了達到最高的安全性,當您的主機環境支援時,使用 免憑證認證(Managed Identity 或 Workload Identity Federation)。
運作方式
- 你可以用私鑰產生或取得 X.509 證書。
- 在你的 Microsoft Entra 應用程式註冊中登錄憑證的 公開金鑰(或指紋)。
- 執行時,Microsoft.Identity.Web 會從你設定的來源載入憑證(包括私鑰)。
- 函式庫使用私鑰簽署客戶端憑證,並傳送至 Microsoft Entra ID 以取得憑證。
憑證來源
Microsoft。Identity.Web 支援從多個來源載入憑證:
| 來源類型 |
SourceType 值 |
最適合 |
|---|---|---|
| Azure Key Vault | KeyVault |
製作(建議) |
| 憑證儲存庫 |
StoreWithThumbprint 或 StoreWithDistinguishedName |
Windows 伺服器,本地端 |
| 檔案路徑 | Path |
開發與容器化應用程式 |
| Base64 編碼字串 | Base64Encoded |
Kubernetes 機密、CI/CD 流水線 |
你可以在ClientCertificates陣列內的AzureAd(或AzureAdB2C)設定區塊中配置憑證。 你可以為輪替情境指定多個憑證——像是 Microsoft。Identity.Web 會使用它找到的第一個有效憑證。
來自 Azure Key Vault (建議)
Azure Key Vault 是生產環境中憑證的推薦來源。 它提供集中管理、存取控制、稽核及自動輪換功能。
Configuration
將憑證設定加入您的 appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCertificates": [
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://your-keyvault-name.vault.azure.net",
"KeyVaultCertificateName": "your-certificate-name"
}
]
}
}
| 房產 | 說明 |
|---|---|
SourceType |
必須是 "KeyVault"。 |
KeyVaultUrl |
你Azure Key Vault的 URI(例如 https://myapp-kv.vault.azure.net)。 |
KeyVaultCertificateName |
存放在 金鑰保存庫 的憑證名稱。 |
設定 金鑰保存庫 存取政策
你的應用程式身份必須有權限讀取 金鑰保存庫 的憑證。 你如何授權這點,取決於你是使用保險庫存取政策模型還是 Azure 角色基礎存取控制(RBAC)。
選項一:資料庫存取政策
az keyvault set-policy \
--name your-keyvault-name \
--object-id <app-or-managed-identity-object-id> \
--certificate-permissions get list \
--secret-permissions get
備註
--secret-permissions get 權限是必要的,因為 Azure Key Vault 將私鑰儲存為與憑證連結的秘密。 Microsoft。Identity.Web 需要同時存取憑證及其私鑰。
Option 2: Azure RBAC
將 金鑰保存庫 憑證使用者角色指派給應用程式的身份:
az role assignment create \
--role "Key Vault Certificate User" \
--assignee <app-or-managed-identity-object-id> \
--scope /subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault-name>
使用管理身份(Managed Identity)來存取 金鑰保存庫
當你的應用程式在 Azure(App Service、Azure Functions、Azure Kubernetes Service、VMs)執行時,請使用 Managed Identity 來認證 金鑰保存庫。 這樣就不需要任何憑證來存取保險庫本身。
系統指派的受管理身份識別
如果你的應用程式啟用了系統指派的管理身份,Microsoft。Identity.Web 會自動使用 DefaultAzureCredential 來驗證給金鑰保存庫。 除了ClientCertificates條目:不需要額外的配置。
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCertificates": [
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://your-keyvault-name.vault.azure.net",
"KeyVaultCertificateName": "your-certificate-name"
}
]
}
}
使用者指派的受控識別
對於使用者指派的管理身份,請在金鑰保存庫憑證描述符上指定 ManagedIdentityClientId:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCertificates": [
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://your-keyvault-name.vault.azure.net",
"KeyVaultCertificateName": "your-certificate-name",
"ManagedIdentityClientId": "user-assigned-managed-identity-client-id"
}
]
}
}
小提示
在開發過程中本地執行時,DefaultAzureCredential 會退回到你的 Azure CLI 或 Visual Studio 憑證。 請確保你已登入 az login,且你的開發者帳號擁有適當的金鑰保存庫權限。
來自憑證儲存庫(僅限 Windows)
在 Windows 上,你可以從 Windows 憑證商店載入憑證。 這在本地部署或 IIS 託管的部署中很常見。
用指紋
請使用 StoreWithThumbprint 憑證的 SHA-1 指紋來識別:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCertificates": [
{
"SourceType": "StoreWithThumbprint",
"CertificateStorePath": "CurrentUser/My",
"CertificateThumbprint": "A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2"
}
]
}
}
| 房產 | 說明 |
|---|---|
SourceType |
必須是 "StoreWithThumbprint"。 |
CertificateStorePath |
證書存儲位置。 常見值: "CurrentUser/My", "LocalMachine/My"。 |
CertificateThumbprint |
憑證的 SHA-1 拇指紋(40 個十六進位字元)。 |
以傑出之名
請使用 StoreWithDistinguishedName 以主旨名稱識別證書:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCertificates": [
{
"SourceType": "StoreWithDistinguishedName",
"CertificateStorePath": "CurrentUser/My",
"CertificateDistinguishedName": "CN=MyAppCertificate"
}
]
}
}
| 房產 | 說明 |
|---|---|
SourceType |
必須是 "StoreWithDistinguishedName"。 |
CertificateStorePath |
證書存儲位置。 常見值: "CurrentUser/My", "LocalMachine/My"。 |
CertificateDistinguishedName |
證書的主題區別名稱(例如,"CN=MyAppCertificate")。 |
證書存放地點
下表列出常見的憑證儲存路徑及其存取權限:
| 路徑 | 說明 | 所需權限 |
|---|---|---|
CurrentUser/My |
目前使用者的個人商店 | 使用者層級存取 |
LocalMachine/My |
全機範圍個人儲存庫 | 管理員存取權 |
LocalMachine/Root |
受信任的根憑證授權中心 | 管理員存取權 |
CurrentUser/Root |
目前使用者受信任的根憑證認證機構 | 使用者層級存取 |
備註
在 IIS 中託管時,應用程式池身份必須能讀取憑證的私鑰。 你可以透過憑證 MMC snap-in 中的 「管理私鑰 」選項來授權。
來自檔案路徑
你可以直接從 .pfx 磁碟上的 (PKCS#12) 檔案載入憑證。
警告
不 建議在生產環境中將憑證檔案存於磁碟上,並在設定中設定密碼。 此方法僅用於本地開發或檔案系統受保護的環境(例如容器中掛載的秘密)。
Configuration
將憑證檔案路徑和密碼加入您的 appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCertificates": [
{
"SourceType": "Path",
"CertificateDiskPath": "/path/to/certificate.pfx",
"CertificatePassword": "your-certificate-password"
}
]
}
}
| 房產 | 說明 |
|---|---|
SourceType |
必須是 "Path"。 |
CertificateDiskPath |
絕對或相對路徑到.pfx 檔案。 |
CertificatePassword |
檔案密碼 .pfx 。 如果憑證沒有密碼,就省略這個屬性或設為空字串。 |
小提示
為避免將密碼以明文儲存在appsettings.json中,請使用環境變數或秘密管理器進行參考:
使用 .NET 使用者秘密(開發):
dotnet user-secrets set "AzureAd:ClientCertificates:0:CertificatePassword" "your-password"
使用環境變數:
export AzureAd__ClientCertificates__0__CertificatePassword="your-password"
根據 Base64 編碼值
你可以提供 Base64 編碼的字串憑證。 這種方法在透過環境變數、Kubernetes 秘密或 CI/CD 管線變數注入憑證時非常有用。
Configuration
將 Base64 編碼的憑證值加到你的 appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCertificates": [
{
"SourceType": "Base64Encoded",
"Base64EncodedValue": "MIIKcQIBAzCCCi0GCSqGSIb3DQEHAaCCCh4Egg..."
}
]
}
}
| 房產 | 說明 |
|---|---|
SourceType |
必須是 "Base64Encoded"。 |
Base64EncodedValue |
完整憑證(包含私鑰)以 Base64 字串編碼。 |
產生 Base64 值
將檔案轉換 .pfx 成 Base64 字串:
PowerShell:
$certBytes = [System.IO.File]::ReadAllBytes("path/to/certificate.pfx")
$base64 = [System.Convert]::ToBase64String($certBytes)
$base64 | Set-Clipboard # Copies to clipboard
Bash:
base64 -w 0 path/to/certificate.pfx
與 Kubernetes 秘密的結合使用
將 Base64 編碼的憑證儲存在 Kubernetes 秘密中,並將其映射到環境變數:
apiVersion: v1
kind: Secret
metadata:
name: app-cert-secret
type: Opaque
data:
AzureAd__ClientCertificates__0__Base64EncodedValue: <base64-encoded-pfx>
引用部署中的機密:
env:
- name: AzureAd__ClientCertificates__0__SourceType
value: "Base64Encoded"
- name: AzureAd__ClientCertificates__0__Base64EncodedValue
valueFrom:
secretKeyRef:
name: app-cert-secret
key: AzureAd__ClientCertificates__0__Base64EncodedValue
在 CI/CD 管線中的應用
在 Azure DevOps 或 GitHub Actions 中,將 Base64 編碼的憑證儲存為秘密變數,然後在執行時將其設為環境變數。
GitHub Actions範例:
env:
AzureAd__ClientCertificates__0__SourceType: "Base64Encoded"
AzureAd__ClientCertificates__0__Base64EncodedValue: ${{ secrets.APP_CERTIFICATE_BASE64 }}
Azure DevOps範例:
variables:
AzureAd__ClientCertificates__0__SourceType: "Base64Encoded"
AzureAd__ClientCertificates__0__Base64EncodedValue: $(AppCertificateBase64)
這很重要
即使憑證是 Base64 編碼,它仍包含私鑰,必須視為秘密。 在 CI/CD 管線中務必使用秘密變數——切勿將 Base64 編碼的憑證提交給原始碼控制。
用 C# 程式碼設定憑證
除了 JSON 設定外,你還可以用 CredentialDescription 的 Microsoft.Identity.Abstractions 類別程式化配置憑證憑證。
Helper 方法集
該 CredentialDescription 類別為每種憑證來源類型提供靜態輔助方法:
using Microsoft.Identity.Abstractions;
// From Azure Key Vault
var kvCredential = CredentialDescription.FromKeyVault(
"https://your-keyvault-name.vault.azure.net",
"your-certificate-name");
// From certificate store (by thumbprint)
var thumbprintCredential = CredentialDescription.FromCertificateStore(
"CurrentUser/My",
thumbprint: "A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2");
// From certificate store (by distinguished name)
var dnCredential = CredentialDescription.FromCertificateStore(
"CurrentUser/My",
distinguishedName: "CN=MyAppCertificate");
// From file path
var pathCredential = CredentialDescription.FromCertificatePath(
"/path/to/certificate.pfx",
"your-certificate-password");
// From Base64-encoded string
var base64Credential = CredentialDescription.FromBase64String(
"MIIKcQIBAzCCCi0GCSqGSIb3DQEHAaCCCh4Egg...");
在 ASP.NET Core 中的應用
在設定認證時,直接傳遞憑證描述:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
options.Instance = "https://login.microsoftonline.com/";
options.TenantId = "your-tenant-id";
options.ClientId = "your-client-id";
options.ClientCredentials = new[]
{
CredentialDescription.FromKeyVault(
"https://your-keyvault-name.vault.azure.net",
"your-certificate-name")
};
});
小提示
輔助方法等同於手動設定物件屬性 CredentialDescription 。 當你用程式碼設定憑證時,它們提供了更簡潔的語法,而不是透過 appsettings.json。
建立自簽名的開發憑證
在本地開發和測試時,你可以建立自簽憑證。 不要在生產環境中使用自簽憑證。
使用 PowerShell(Windows)
執行以下指令建立自簽憑證,匯出並顯示拇指紋:
$cert = New-SelfSignedCertificate `
-Subject "CN=MyDevCertificate" `
-CertStoreLocation "Cert:\CurrentUser\My" `
-KeyExportPolicy Exportable `
-KeySpec Signature `
-KeyLength 2048 `
-KeyAlgorithm RSA `
-HashAlgorithm SHA256 `
-NotAfter (Get-Date).AddYears(2)
# Export the .pfx file (with private key)
$password = ConvertTo-SecureString -String "YourPassword123!" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath ".\MyDevCertificate.pfx" -Password $password
# Export the .cer file (public key only — for app registration)
Export-Certificate -Cert $cert -FilePath ".\MyDevCertificate.cer"
# Display the thumbprint
Write-Host "Thumbprint: $($cert.Thumbprint)"
使用 OpenSSL(跨平台)
執行以下指令產生憑證,將其打包成 .pfx 檔案,並顯示指紋:
# Generate a self-signed certificate and private key
openssl req -x509 -newkey rsa:2048 \
-keyout key.pem -out cert.pem \
-days 730 -nodes \
-subj "/CN=MyDevCertificate"
# Package into a .pfx file
openssl pkcs12 -export \
-out MyDevCertificate.pfx \
-inkey key.pem -in cert.pem \
-passout pass:YourPassword123!
# Get the thumbprint
openssl x509 -in cert.pem -noout -fingerprint -sha1
使用 .NET CLI
將開發 HTTPS 憑證匯出為 .pfx 檔案:
dotnet dev-certs https --export-path ./MyDevCertificate.pfx --password YourPassword123!
備註
該 dotnet dev-certs 指令會產生 HTTPS 開發憑證。 雖然可用於測試憑證載入,但主要用於本地 HTTPS,可能不適合所有認證測試場景。
在 Microsoft Entra ID 上註冊證書
在建立或取得憑證後,您必須在 Microsoft Entra ID 中與應用程式註冊一同註冊其公鑰。
使用 Azure 入口網站
- 前往Azure入口並導航到Microsoft Entra ID>應用程式註冊。
- 選取您的應用程式。
- 選取 [憑證和祕密]>[憑證]>[上傳憑證]。
- 上傳
.cer或.pem檔案,其中只包含公鑰。 不要上傳.pfx包含私鑰的檔案。 - 請注意上傳後顯示的 Thumbprint 值——你可能需要它來設定。
使用 Azure CLI
az ad app credential reset \
--id <application-client-id> \
--cert @/path/to/certificate.pem \
--append
--append旗標會新增憑證,卻不會移除現有憑證。
使用 Microsoft Graph PowerShell
$certData = [System.IO.File]::ReadAllBytes(".\MyDevCertificate.cer")
$base64Cert = [System.Convert]::ToBase64String($certData)
$keyCredential = @{
type = "AsymmetricX509Cert"
usage = "Verify"
key = [System.Convert]::FromBase64String($base64Cert)
displayName = "MyAppCertificate"
}
Update-MgApplication -ApplicationId <app-object-id> -KeyCredentials @($keyCredential)
這很重要
只把公鑰.cer(或.pem)上傳到應用程式註冊時。 切勿上傳 .pfx 包含私鑰的檔案。 私鑰必須安全儲存,且僅對您的應用程式開放。
憑證輪替
憑證輪替會在到期前用新的憑證替換,確保服務不中斷。
策略:證書重疊
建議的方式是使用互相重疊的有效期限:
- 在現有證書到期前(例如提前30至60天)產生新證書。
- 將新憑證與現有憑證一起註冊在Microsoft Entra應用程式註冊中。 Microsoft Entra ID 接受由任何註冊憑證簽署的憑證。
- 將新的憑證部署到應用程式的憑證來源(金鑰保存庫、憑證儲存等)。
- 更新設定 (如有需要)指向新憑證。
- 確認所有實例都使用新憑證後,從應用程式註冊中移除舊憑證。
配置中的多個憑證
Microsoft。Identity.Web 支援指定多重憑證。 程式庫依序嘗試,並使用第一個有效憑證:
{
"AzureAd": {
"ClientCertificates": [
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://your-keyvault.vault.azure.net",
"KeyVaultCertificateName": "new-cert-2026"
},
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://your-keyvault.vault.azure.net",
"KeyVaultCertificateName": "current-cert-2025"
}
]
}
}
使用 Azure Key Vault 的自動輪替
Azure Key Vault 支援自動憑證更新。 當你啟用自動旋轉時:
- 金鑰保存庫 會在過期前產生新的憑證版本。
- Microsoft。Identity.Web 會在下一次憑證擷取時自動擷取最新版本。
- 舊的憑證版本會一直有效直到到期。
要在 金鑰保存庫 中設定自動旋轉:
az keyvault certificate set-attributes \
--vault-name your-keyvault-name \
--name your-certificate-name \
--policy @rotation-policy.json
小提示
對於具有長時間執行程序的應用程式,建議考慮實施定期憑證更新。 Microsoft。Identity.Web 會將憑證快取到記憶體中。 如果憑證在 金鑰保存庫 中被輪換,應用程式下次需要建立新的 MSAL 機密用戶端應用程式實例時,會取用該憑證。
針對憑證錯誤進行疑難排解
本節列出常見錯誤訊息及其解決方案。
常見錯誤
找不到憑證
錯誤訊息:
System.Security.Cryptography.CryptographicException: The certificate cannot be found.
可能的原因與解決方法:
| 原因 | 解決方案 |
|---|---|
| 指紋不正確 | 確認你設定中的指紋與已安裝的憑證相符。 移除所有隱藏字元(空格、隱形的 Unicode)。 |
| 錯誤的憑證存儲區 | 確認 CertificateStorePath 憑證安裝地點的匹配(CurrentUser/My 與 LocalMachine/My。 |
| 憑證未安裝 | 請使用 certmgr.msc (CurrentUser) 或 certlm.msc (LocalMachine) 將憑證匯入正確的儲存庫。 |
| 金鑰保存庫 名稱不符 | 請確認 KeyVaultUrl 並 KeyVaultCertificateName 正確。 |
| 找不到檔案 | 確認 CertificateDiskPath 指向現有 .pfx 檔案,應用程式就有讀取權限。 |
金鑰保存庫 存取被拒
錯誤訊息:
Azure.RequestFailedException: The user, group or application '...' does not have certificates get permission on key vault '...'
解決方案:
- 驗證存取政策同時授予
get憑證與秘密權限。 - 若使用 Azure RBAC,請確保身份具有 金鑰保存庫憑證使用者角色。
- 對於管理身份,請確認身份已啟用且政策中使用正確的物件 ID。
憑證私鑰無法存取
錯誤訊息:
System.Security.Cryptography.CryptographicException: Keyset does not exist.
解決方案:
- 在 Windows/IIS 中,確保應用程式集區身分擁有讀取私鑰的存取權。 使用憑證 MMC 的 snap-in 透過 管理私鑰授權存取權限。
- 在 Linux 上,請確認該
.pfx檔案是否具備適當的檔案權限(chmod 600)。 - 確保憑證是以私鑰
Export-PfxCertificate(或openssl pkcs12 -export)匯出的。
憑證已過期
錯誤訊息:
AADSTS700027: Client assertion contains an invalid signature. The key was expired.
解決方案:
- 請檢查證書的有效期限:
openssl x509 -in cert.pem -noout -dates。 - 產生新的憑證,並更新應用程式註冊和應用程式設定。
- 實施憑證輪替以防止未來過期問題。 請參閱 證書輪替。
錯誤的憑證密碼
錯誤訊息:
System.Security.Cryptography.CryptographicException: The specified network password is not correct.
解決方案:
- Verify
CertificatePassword與.pfx匯出檔案時使用的密碼相符。 - 如果使用環境變數,請檢查是否有編碼問題(如後方換行、特殊字元)。
- 用已知密碼重新匯出憑證。
診斷檢查清單
當憑證驗證無法運作時,請使用這份檢查清單:
- [ ] 證書有效性 — 證書是否在有效期內? 檢查
NotBefore和NotAfter日期。 - [ ] 應用程式註冊 — 憑證的公鑰是否已上傳到正確的應用程式註冊?
- [ ] 指紋匹配 — 你設定中的指紋是否與應用程式註冊中的憑證相符?
- [ ] 私鑰存取 — 申請程序能否讀取憑證的私鑰?
- [ ] 金鑰保存庫 權限 — 對於金鑰保存庫來源,身份是否同時擁有
certificates/get與secrets/get權限? - [ ] 設定區 — 憑證設定是否屬於正確的區段(
AzureAd或AzureAdB2C)? - [ ] NuGet packages —
Microsoft.Identity.Web是最新的嗎? 舊版本可能不支援某些憑證來源類型。
啟用 記錄
要取得詳細診斷資訊,請啟用 MSAL 記錄:
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
builder.Logging.AddFilter("Microsoft.Identity", LogLevel.Debug);
檢視日誌中有關憑證載入、客戶端聲明建立及令牌取得的訊息。