使用 Microsoft.Identity.Web 的憑證

Microsoft。Identity.Web 支援憑證式認證,作為機密用戶端應用程式中用戶端秘密的安全替代方案。 憑證使用非對稱密碼學,因此只有私鑰持有者能進行認證。

在本文中,你將從各種來源設定憑證憑證,註冊到你的應用程式,並在生產環境中加以管理。

為什麼要使用憑證?

因素 用戶端密碼 證書
安全性 共享密鑰(對稱) 非對稱金鑰對
旋轉 需要重新部署應用程式或更改設定 可透過 金鑰保存庫 自動化
暴露風險 設定中的秘密可能會被洩漏 私鑰會保存在安全儲存中
合規性 可能不符合企業政策 符合大多數企業安全需求
推薦用於 開發與原型製作 生產工作負載

這很重要

Microsoft 建議在生產應用程式中使用憑證而非用戶端秘密。 為了達到最高的安全性,當您的主機環境支援時,使用 免憑證認證(Managed Identity 或 Workload Identity Federation)。

運作方式

  1. 你可以用私鑰產生或取得 X.509 證書。
  2. 在你的 Microsoft Entra 應用程式註冊中登錄憑證的 公開金鑰(或指紋)。
  3. 執行時,Microsoft.Identity.Web 會從你設定的來源載入憑證(包括私鑰)。
  4. 函式庫使用私鑰簽署客戶端憑證,並傳送至 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 是生產環境中憑證的推薦來源。 它提供集中管理、存取控制、稽核及自動輪換功能。

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 入口網站

  1. 前往Azure入口並導航到Microsoft Entra ID>應用程式註冊。
  2. 選取您的應用程式。
  3. 選取 [憑證和祕密]>[憑證]>[上傳憑證]。
  4. 上傳.cer或.pem檔案,其中只包含公鑰。 不要上傳 .pfx 包含私鑰的檔案。
  5. 請注意上傳後顯示的 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 包含私鑰的檔案。 私鑰必須安全儲存,且僅對您的應用程式開放。


憑證輪替

憑證輪替會在到期前用新的憑證替換,確保服務不中斷。

策略:證書重疊

建議的方式是使用互相重疊的有效期限:

  1. 在現有證書到期前(例如提前30至60天)產生新證書。
  2. 將新憑證與現有憑證一起註冊在Microsoft Entra應用程式註冊中。 Microsoft Entra ID 接受由任何註冊憑證簽署的憑證。
  3. 將新的憑證部署到應用程式的憑證來源(金鑰保存庫、憑證儲存等)。
  4. 更新設定 (如有需要)指向新憑證。
  5. 確認所有實例都使用新憑證後,從應用程式註冊中移除舊憑證。

配置中的多個憑證

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 支援自動憑證更新。 當你啟用自動旋轉時:

  1. 金鑰保存庫 會在過期前產生新的憑證版本。
  2. Microsoft。Identity.Web 會在下一次憑證擷取時自動擷取最新版本。
  3. 舊的憑證版本會一直有效直到到期。

要在 金鑰保存庫 中設定自動旋轉:

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);

檢視日誌中有關憑證載入、客戶端聲明建立及令牌取得的訊息。