分享方式:


在 Node.js Web 應用程式中使用用戶端憑證

適用於具有灰色 X 符號的白色圓圈。員工租用戶內含白色核取記號的綠色圓圈。 外部租用戶 (深入了解)

Microsoft Entra External ID 支援兩種類型的驗證,機密用戶端應用程式;密碼型驗證 (例用戶端密碼) 和憑證式驗證。 為了提高安全性層級,建議您使用憑證 (而不是用戶端密碼) 作為機密用戶端應用程式中的認證。

在生產環境中,您應該購買由已知憑證頒發機構單位簽署的憑證,然後使用 Azure Key Vault 來管理憑證存取和存留期。 不過,基於測試目的,您可以建立自我簽署憑證,並將您的應用程式設定為向它進行驗證。

在本文中,您將了解如何在 Azure 入口網站、OpenSSL 或 PowerShell 上使用 Azure Key Vault 來產生自我簽署憑證。 如果您已經有用戶端密碼,您將了解如何安全地刪除它。

如有需要,您也可以使用 .NETNode.jsGoPythonJava 用戶端連結庫,以程式設計方式建立自我簽署憑證。

必要條件

建立自我簽署憑證

如果您的本機電腦中有現有的自我簽署憑證,您可以略過此步驟,然後繼續將憑證上傳至您的應用程式註冊

您可以使用 Azure Key Vault 為您的應用程式產生自我簽署憑證。 藉由使用 Azure Key Vault,您可以享有的權益包括指派合作夥伴憑證頒發機構單位 (CA) 和自動化憑證輪替。

如果您在 Azure Key Vault 中有擁有的自我簽署憑證,而且您想要在不下載的情況下使用,請略過此步驟,然後繼續直接從 Azure Key Vault 使用自我簽署憑證。 否則,請使用下列步驟來產生您的憑證

  1. 請遵循從 Azure Key Vault 設定及擷取憑證中的步驟,使用 Azure 入口網站建立和下載憑證。

  2. 建立憑證之後,請下載 .cer 檔案和 .pfx 檔案,例如 ciam-client-app-cert.cerciam-client-app-cert.pfx.cer 檔案包含公開金鑰,以及您上傳至 Microsoft Entra 系統管理中心的內容。

  3. 在您的終端機中,執行下列命令,從 .pfx 檔案擷取私密金鑰。 當系統提示您輸入複雜密碼時,如果您就不想設定,按下 Enter 鍵即可。 否則,請輸入您選擇的複雜密碼時:

    openssl pkcs12 -in ciam-client-app-cert.pfx -nocerts -out ciam-client-app-cert.key
    

    ciam-client-app-cert.key 檔案是您在應用程式中使用的內容。

上傳憑證至註冊應用程式

若要使用用戶端應用程式憑證,您必須將您在 Microsoft Entra 系統管理中心註冊的應用程式與憑證產生關聯:

  1. 至少以應用程式系統管理員 (部分機器翻譯) 的身分登入 Microsoft Entra 系統管理中心

  2. 如果您有多個租用戶的存取權,請使用頂端功能表中的 [設定] 圖示 ,從 [目錄 + 訂用帳戶] 功能表切換至您的外部租用戶。

  3. 瀏覽至 [身分識別]>[應用程式]>[應用程式註冊]

  4. 從應用程式註冊清單中,選取您想要與憑證建立關聯的應用程式,例如 ciam-client-app

  5. 在 [管理] 下,選取 [憑證和密碼]

  6. 取 [憑證],接著選取 [上傳憑證]

  7. 選取 [選取檔案] 檔案圖示,然後選取您要上傳的憑證,例如 ciam-client-app-cert.pemciam-client-app-cert.cerciam-client-app-cert.crt

  8. 針對 [描述],輸入描述,例如,CIAM 用戶端應用程式憑證,然後選取 [新增] 以上傳您的憑證。 上傳憑證之後,即會顯示指紋開始日期到期值。

  9. 記錄指紋 值,以供稍後在設定用戶端應用程式時使用。

如果您的應用程式已經有用戶端密碼,您必須將其刪除,以避免惡意應用程式模擬應用程式:

  1. 移至 [用戶端密碼] 索引標籤,然後選取 [刪除] 圖示。
  2. 在出現的快顯視窗中,選取 [是]

將您的 Node.js 應用程式設定為使用憑證

將應用程式註冊與憑證產生關聯之後,您必須更新應用程式程式代碼以開始使用憑證:

  1. 找出包含 MSAL 設定物件的檔案,例如 authConfig.js 中的 msalConfig,然後更新,使其看起來類似下列程式碼。 如果您有用戶端密碼存在,請務必將其移除:

    require('dotenv').config();
    const fs = require('fs'); //// import the fs module for reading the key file
    const crypto = require('crypto');
    const TENANT_SUBDOMAIN = process.env.TENANT_SUBDOMAIN || 'Enter_the_Tenant_Subdomain_Here';
    const REDIRECT_URI = process.env.REDIRECT_URI || 'http://localhost:3000/auth/redirect';
    const POST_LOGOUT_REDIRECT_URI = process.env.POST_LOGOUT_REDIRECT_URI || 'http://localhost:3000';
    
    const privateKeySource = fs.readFileSync('PATH_TO_YOUR_PRIVATE_KEY_FILE')
    
    const privateKeyObject = crypto.createPrivateKey({
        key: privateKeySource,
        passphrase: 'Add_Passphrase_Here',
        format: 'pem'
    });
    
    const privateKey = privateKeyObject.export({
        format: 'pem',
        type: 'pkcs8'
    });
    
    /**
     * Configuration object to be passed to MSAL instance on creation.
     * For a full list of MSAL Node configuration parameters, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md
     */
        const msalConfig = {
            auth: {
                clientId: process.env.CLIENT_ID || 'Enter_the_Application_Id_Here', // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
                authority: process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, 
                clientCertificate: {
                    thumbprint: "YOUR_CERT_THUMBPRINT", // replace with thumbprint obtained during step 2 above
                    privateKey: privateKey
                }
            },
            //... Rest of code in the msalConfig object
        };
    
    module.exports = {
        msalConfig,
        REDIRECT_URI,
        POST_LOGOUT_REDIRECT_URI,
        TENANT_SUBDOMAIN
    };
    

    在您的程式碼中,取代預留位置:

    • 使用加密私密金鑰的複雜密碼來 Add_Passphrase_Here

    • 使用稍早記錄的指紋值來 YOUR_CERT_THUMBPRINT

    • 使用前往私密金鑰的檔案路徑來 PATH_TO_YOUR_PRIVATE_KEY_FILE

    • 您稍早所註冊應用程式的 Enter_the_Application_Id_Here 應用程式 (用戶端) 識別碼。

    • Enter_the_Tenant_Subdomain_Here 並將它取代為 Directory (租用戶) 子網域。 例如,如果您的租用戶主要網域是 contoso.onmicrosoft.com,請使用 contoso。 如果您沒有租用戶名稱,請了解如何閱讀租用戶詳細資料

    我們已將金鑰加密 (建議您這麼做),因此我們必須在傳遞至 MSAL 設定物件之前先將其解密。

    //...
    const privateKeyObject = crypto.createPrivateKey({
        key: privateKeySource,
        passphrase: 'Add_Passphrase_Here',
        format: 'pem'
    });
    
    const privateKey = privateKeyObject.export({
        format: 'pem',
        type: 'pkcs8'
    });
    //...
    
  2. 使用執行及測試 Web 應用程式中的步驟來測試您的應用程式。

直接從 Azure Key Vault 使用自我簽署憑證

您可以直接從 Azure Key Vault 使用現有憑證:

  1. 找出包含 MSAL 設定物件的檔案,例如 authConfig.js 中的 msalConfig,然後移除 clientSecret 屬性:

    const msalConfig = {
        auth: {
            clientId: process.env.CLIENT_ID || 'Enter_the_Application_Id_Here', // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
            authority: process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, 
        },
        //...
    };
    
  2. 安裝 Azure CLI,然後在您的控制台上輸入下列命令進行登入:

    az login --tenant YOUR_TENANT_ID
    

    以您稍早複製的 Directory (租用戶) 識別碼取代預留位置 YOUR_TENANT_ID

  3. 在您的主控台,輸入下列命令以安裝必要的套件:

    npm install --save @azure/identity @azure/keyvault-certificates @azure/keyvault-secrets
    
  4. 在您的用戶端應用程式中,使用下列程式代碼來產生 thumbprintprivateKey

    const identity = require("@azure/identity");
    const keyvaultCert = require("@azure/keyvault-certificates");
    const keyvaultSecret = require('@azure/keyvault-secrets');
    
    const KV_URL = process.env["KEY_VAULT_URL"] || "ENTER_YOUR_KEY_VAULT_URL"
    const CERTIFICATE_NAME = process.env["CERTIFICATE_NAME"] || "ENTER_THE_NAME_OF_YOUR_CERTIFICATE_ON_KEY_VAULT";
    
    // Initialize Azure SDKs
    const credential = new identity.DefaultAzureCredential();
    const certClient = new keyvaultCert.CertificateClient(KV_URL, credential);
    const secretClient = new keyvaultSecret.SecretClient(KV_URL, credential);
    
    async function getKeyAndThumbprint() {
    
        // Grab the certificate thumbprint
        const certResponse = await certClient.getCertificate(CERTIFICATE_NAME).catch(err => console.log(err));
        const thumbprint = certResponse.properties.x509Thumbprint.toString('hex')
    
        // When you upload a certificate to Key Vault, a secret containing your private key is automatically created
        const secretResponse = await secretClient.getSecret(CERTIFICATE_NAME).catch(err => console.log(err));;
    
        // secretResponse contains both public and private key, but we only need the private key
        const privateKey = secretResponse.value.split('-----BEGIN CERTIFICATE-----\n')[0]
    }
    
    getKeyAndThumbprint();        
    

    在您的程式碼中,取代預留位置:

    • 使用您的 Azure Key Vault URL 進行 ENTER_YOUR_KEY_VAULT_URL

    • 使用 Azure 金鑰保存庫中的憑證名稱進行 ENTER_THE_NAME_OF_YOUR_CERTIFICATE_ON_KEY_VAULT

  5. 使用 thumbprintprivateKey 值來更新您的設定:

    let clientCert = {
        thumbprint: thumbprint, 
        privateKey: privateKey,
    };
    
    msalConfig.auth.clientCertificate = clientCert; //For this to work, you can't declares your msalConfig using const modifier 
    
  6. 然後繼續具現化保密用戶端,如 getMsalInstance 方法所示:

    class AuthProvider {
        //...
        getMsalInstance(msalConfig) {
            return new msal.ConfidentialClientApplication(msalConfig);
        }
        //...
    }
    
  7. 使用執行及測試 Web 應用程式中的步驟來測試您的應用程式。

下一步

了解如何: