共用方式為


Microsoft 身分識別平台和 OAuth 2.0 用戶端認證流程

OAuth 2.0 用戶端認證授與流程可允許 Web 服務 (機密用戶端) 在呼叫其他 Web 服務時,使用自己的認證來驗證,而不是藉由模擬使用者。 RFC 6749 中所指定的授與 (有時稱為「雙方 OAuth」) 可以用來存取 Web 裝載資源,方法是使用應用程式的身分識別。 此類型通常用於必須在背景中執行 (不需與使用者直接互動) 的伺服器對伺服器互動,通常稱為「精靈」或「服務帳戶」

在用戶端認證流程中,管理員會直接將權限授與應用程式本身。 當應用程式向資源出示權杖時,資源會強制要求應用程式本身具備執行動作的授權,因為使用者不會參與驗證。 本文涵蓋執行下列作業所需的兩個步驟:

本文說明如何在您的應用程式中直接針對通訊協定進行程式設計。 建議您盡可能改為使用支援的 Microsoft 驗證程式庫 (MSAL),以取得權杖並呼叫受保護的 Web API。 您也可以參照使用 MSAL 的範例應用程式。 請注意,重新整理權杖一律不會在此流程中授與,因為 client_idclient_secret (取得重新整理權杖時需要這兩項) 可改為用來取得存取權杖。

對於較高層級的保證,Microsoft 身分識別平台也可讓呼叫端服務使用憑證或同盟認證 (而非共用祕密) 來進行認證。 因為將會使用應用程式自己的認證,所以這些認證必須保持安全。 「永遠不要」在原始程式碼中發佈該認證、將其內嵌在網頁中,或將其用於廣泛散發的原生應用程式中。

通訊協定圖表

整個用戶端認證流程看起來類似下圖。 我們會在本文稍後說明每個步驟。

圖:顯示用戶端認證流程

取得直接授權

應用程式通常會收到直接授權,而可透過下列兩種方式之一存取資源:

這兩種方法是 Microsoft Entra ID 中最常見的方法,並建議用於執行用戶端認證流程的用戶端和資源。 資源也可以選擇以其他方法授權其用戶端。 每個資源伺服器都可以選擇最適合其應用程式的方法。

存取控制清單

資源提供者可能會根據它所知的應用程式 (用戶端) 識別碼清單,強制執行授權檢查並授與特定層級的存取權。 資源在從 Microsoft 身分識別平台收到權杖時,可以將此權杖解碼,並從 appidiss 宣告中擷取用戶端的應用程式識別碼。 然後,它會將應用程式與它所保有的存取控制清單 (ACL) 進行比較。 各資源之間的 ACL 細微性及方法可能有極大的差異。

常見的使用案例是使用 ACL 來針對 Web 應用程式或 Web API 執行測試。 Web API 可能只會將完整權限中的一部分授與特定用戶端。 若要在 API 上執行端對端測試,您可以建立測試用戶端以從 Microsoft 身分識別平台取得權杖,然後將其傳送至 API。 接著,API 會檢查 ACL 是否有測試用戶端的應用程式識別碼,以便提供 API 完整功能的完整存取權。 如果您使用這類 ACL,請務必不要只驗證呼叫者的 appid 值,還要驗證權杖的 iss 值是否可信任。

對於需要存取具有個人 Microsoft 帳戶之取用者使用者所擁有資料的精靈和服務帳戶來說,這種授權相當常見。 對於組織所擁有的資料,建議您透過應用程式權限取得必要的授權。

在沒有 roles 宣告的情況下控制權杖

若要啟用此 ACL 型授權模式,Microsoft Entra ID 不需要授權應用程式即可取得另一個應用程式的權杖。 因此,您可以在沒有 roles 宣告的情況下發出僅限應用程式權杖。 可公開 API 的應用程式必須實作權限檢查,才能接受權杖。

如果您想要防止應用程式為您的應用程式取得無角色僅限應用程式存取權杖,則請確定已啟用您應用程式的指派需求。 這將會封鎖未指派角色的使用者和應用程式,使其無法取得此應用程式的權杖。

應用程式權限

您可以不使用 ACL,而是使用 API 來公開一組「應用程式權限」。 這些是由組織的系統管理員授與應用程式,並且只能用來存取該組織和其員工所擁有的資料。 例如,Microsoft Graph 會公開數個可執行下列操作的應用程式權限︰

  • 讀取所有信箱中的郵件
  • 讀取和寫入所有信箱中的郵件
  • 以任何使用者身分傳送郵件
  • 讀取目錄資料

若要搭配使用應用程式角色 (應用程式權限) 與您自己的 API (而不是 Microsoft Graph),您必須先在 Microsoft Entra 系統管理中心的 API 應用程式註冊中公開應用程式角色。 然後,設定必要的應用程式角色,方法是在用戶端應用程式的應用程式註冊中選取這些權限。 如果您尚未在 API 的應用程式註冊中公開任何應用程式角色,則無法在 Microsoft Entra 系統管理中心內用戶端應用程式的應用程式註冊中指定該 API 的應用程式權限。

驗證為應用程式 (而非使用者) 時,您無法使用委派的權限,因為您的應用程式沒有任何使用者可代表處理的作業。 您必須使用管理員或 API 擁有者所授與的應用程式權限,也稱為應用程式角色。

如需應用程式權限的詳細資訊,請參閱權限與同意

通常,當您建置使用應用程式權限的應用程式時,應用程式會需要一個可供系統管理員核准應用程式權限的頁面或檢視。 此頁面可以是應用程式登入流程的一部分、應用程式設定的一部分,或專用「連線」流程的一部分。 只在使用者使用公司或學校 Microsoft 帳戶登入之後才顯示此 [連接] 檢視十分合理。

如果您將使用者登入應用程式,則可以先識別使用者所屬的組織,再要求使用者核准應用程式權限。 雖然這並非絕對必要,但這麼做可協助您為使用者建立更直覺式的體驗。 若要將使用者登入,請遵循 Microsoft 身分識別平台通訊協定教學課程

向目錄管理員要求權限

當您已準備好向組織管理員要求權限時,可以將使用者重新導向至 Microsoft 身分識別平台「管理員同意端點」

// Line breaks are for legibility only.

GET https://login.microsoftonline.com/{tenant}/adminconsent?
client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&state=12345
&redirect_uri=http://localhost/myapp/permissions

Pro 提示:請嘗試將下列要求貼入瀏覽器中。

https://login.microsoftonline.com/common/adminconsent?client_id=00001111-aaaa-2222-bbbb-3333cccc4444&state=12345&redirect_uri=http://localhost/myapp/permissions
參數 條件 描述
tenant 必要 您想要從中要求權限的目錄租用戶。 這可以採用 GUID 或易記名稱格式。 如果您不知道使用者屬於哪個租用戶,而想要讓他們以任何租用戶登入,請使用 common
client_id 必要 Microsoft Entra 系統管理中心 - 應用程式註冊體驗指派給您應用程式的「應用程式 (用戶端) 識別碼」
redirect_uri 必要 您想要將回應傳送至其中,讓應用程式處理的重新導向 URI。 它必須與您在入口網站中註冊的其中一個重新導向 URI 完全相符,只是它必須採用 URL 編碼,並且可以有額外的路徑區段。
state 建議需求 要求中包含的值,也會隨權杖回應傳回。 它可以是您所想要內容中的字串。 此狀態用於在驗證要求出現之前,於應用程式中編碼使用者的狀態資訊,例如之前所在的網頁或檢視。

此時,Microsoft Entra ID 會強制只有租用戶系統管理員才能登入來完成要求。 系統會請系統管理員核准您在應用程式註冊入口網站中,為您應用程式要求的所有直接應用程式權限。

成功回應

如果系統管理員為您的應用程式核准權限,則成功的回應看起來會像這樣︰

GET http://localhost/myapp/permissions?tenant=aaaabbbb-0000-cccc-1111-dddd2222eeee&state=state=12345&admin_consent=True
參數 描述
tenant 將應用程式所要求的權限授與應用程式的目錄租用戶 (採用 GUID 格式)。
state 一個包含在要求中而將一併在權杖回應中傳回的值。 它可以是您所想要內容中的字串。 此狀態用於在驗證要求出現之前,於應用程式中編碼使用者的狀態資訊,例如之前所在的網頁或檢視。
admin_consent 設定為 [True]
回覆錯誤

如果系統管理員沒有為您的應用程式核准權限,則失敗的回應看起來會像這樣︰

GET http://localhost/myapp/permissions?error=permission_denied&error_description=The+admin+canceled+the+request
參數 描述
error 您可用來分類錯誤類型並對錯誤做出反應的錯誤碼字串。
error_description 可協助您識別錯誤根本原因的特定錯誤訊息。

從應用程式佈建端點收到成功回應後,您的應用程式便已取得它所要求的直接應用程式權限。 現在,您可以針對您想要的資源要求權杖。

取得權杖

取得應用程式的必要授權後,請繼續取得 API 的存取權杖。 若要使用用戶端認證授與來取得權杖,請將 POST 要求傳送至 /token Microsoft 身分識別平台。 有幾個不同的案例:

第一個案例:含有共用祕密的存取權杖要求

POST /{tenant}/oauth2/v2.0/token HTTP/1.1           //Line breaks for clarity
Host: login.microsoftonline.com:443
Content-Type: application/x-www-form-urlencoded

client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret=qWgdYAmab0YSkuL1qKv5bPX
&grant_type=client_credentials
# Replace {tenant} with your tenant!
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=00001111-aaaa-2222-bbbb-3333cccc4444&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=A1bC2dE3f...&grant_type=client_credentials' 'https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token'
參數 條件 描述
tenant 必要 應用程式預期要對其執行作業的目錄租用戶 (以 GUID 或網域名稱格式)。
client_id 必要 指派給應用程式的應用程式識別碼。 您可以在用來註冊應用程式的入口網站中找到這項資訊。
scope 必要 在這個要求中針對 scope 參數傳遞的值應該是您所要資源的資源識別碼 (應用程式識別碼 URI),並附加 .default 尾碼。 所含的所有範圍都必須用於單一資源。 包括多個資源的範圍將會導致錯誤。
就 Microsoft Graph 範例而言,值為 https://graph.microsoft.com/.default。 此值會告知 Microsoft 身分識別平台有關您已為應用程式設定的所有直接應用程式權限,而端點應該會針對與您所要使用資源相關聯的權限發出權杖。 若要深入了解有關 /.default 範圍,請參閱同意文件
client_secret 必要 您在應用程式註冊入口網站中為應用程式產生的用戶端密碼。 用戶端密碼必須在傳送之前先進行 URL 編碼。 在授權標頭中,也支援根據 RFC 6749 提供認證的基本驗證模式。
grant_type 必要 必須設定為 client_credentials

第二個案例:含有憑證的存取權杖要求

POST /{tenant}/oauth2/v2.0/token HTTP/1.1               // Line breaks for clarity
Host: login.microsoftonline.com:443
Content-Type: application/x-www-form-urlencoded

scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_id=11112222-bbbb-3333-cccc-4444dddd5555
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsIng1dCI6Imd4OHRHeXN5amNScUtqRlBuZDdSRnd2d1pJMCJ9.eyJ{a lot of characters here}M8U3bSUKKJDEg
&grant_type=client_credentials
參數 條件 描述
tenant 必要 應用程式預期要對其執行作業的目錄租用戶 (以 GUID 或網域名稱格式)。
client_id 必要 指派給應用程式的應用程式 (用戶端) 識別碼。
scope 必要 在這個要求中針對 scope 參數傳遞的值應該是您所要資源的資源識別碼 (應用程式識別碼 URI),並附加 .default 尾碼。 所含的所有範圍都必須用於單一資源。 包括多個資源的範圍將會導致錯誤。
就 Microsoft Graph 範例而言,值為 https://graph.microsoft.com/.default。 此值會告知 Microsoft 身分識別平台有關您已為應用程式設定的所有直接應用程式權限,而端點應該會針對與您所要使用資源相關聯的權限發出權杖。 若要深入了解有關 /.default 範圍,請參閱同意文件
client_assertion_type 必要 此值必須設為 urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion 必要 您需要建立並使用憑證 (已註冊為應用程式認證) 來簽署的判斷提示 (JSON Web 權杖)。 請參閱憑證認證,以了解如何註冊您的憑證與判斷提示的格式。
grant_type 必要 必須設定為 client_credentials

憑證型要求的參數只有一個部分與共用秘密型要求不同:client_secret 參數已取代為 client_assertion_typeclient_assertion 參數。

第三個案例:具有同盟認證的存取權杖要求

POST /{tenant}/oauth2/v2.0/token HTTP/1.1               // Line breaks for clarity
Host: login.microsoftonline.com:443
Content-Type: application/x-www-form-urlencoded

scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_id=11112222-bbbb-3333-cccc-4444dddd5555&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsIng1dCI6Imd4OHRHeXN5amNScUtqRlBuZDdSRnd2d1pJMCJ9.eyJ{a lot of characters here}M8U3bSUKKJDEg
&grant_type=client_credentials
參數 條件 描述
client_assertion 必要 您的應用程式從 Microsoft 身分識別平台外部的另一個身分識別提供者 (例如 Kubernetes) 所取得的判斷提示 (JWT 或 JSON Web 權杖)。 此 JWT 的細節必須在您的應用程式上註冊為同盟身分識別認證。 請參閱工作負載身分識別同盟,以了解如何設定和使用從其他身分識別提供者產生的判斷提示。

要求中的所有項目都與憑證型流程相同,但有一個重要的例外:client_assertion 的來源。 在此流程中,您的應用程式不會自行建立 JWT 判斷提示。 相反地,您的應用程式會使用另一個身分識別提供者所建立的 JWT。 這稱為工作負載身分識別同盟,其中,會使用另一個身分識別平台中的應用程式身分識別來取得 Microsoft 身分識別平台內的權杖。 這最適合跨雲端案例,例如在 Azure 外部裝載您的計算,但存取 Microsoft 身分識別平台所保護的 API。 如需其他身分識別提供者所建立之必要 JWT 格式的相關資訊,請參閱判斷提示格式

成功回應

任何方法的成功回應如下所示:

{
  "token_type": "Bearer",
  "expires_in": 3599,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBP..."
}
參數 描述
access_token 要求的存取權杖。 應用程式可以使用這個權杖向受保護的資源 (例如 Web API) 進行驗證。
token_type 指出權杖類型的值。 Microsoft 身分識別平台唯一支援的類型為 bearer
expires_in 存取權杖的有效時間長度 (以秒為單位)。

警告

請勿在程式碼中,嘗試驗證或讀取任何您未擁有的 API 的權杖 (包括此範例中的權杖)。 Microsoft 服務的權杖可以使用不會驗證為 JWT 的特殊格式,且可能為取用者 (Microsoft 帳戶) 使用者進行加密。 雖然讀取權杖是很實用的偵錯與學習工具,但請勿在程式碼中依賴此功能的相依性,或是假設並非用於您所控制 API 的權杖相關內容。

回覆錯誤

錯誤回應 (400 不正確的要求) 如下所示:

{
  "error": "invalid_scope",
  "error_description": "AADSTS70011: The provided value for the input parameter 'scope' is not valid. The scope https://foo.microsoft.com/.default is not valid.\r\nTrace ID: 0000aaaa-11bb-cccc-dd22-eeeeee333333\r\nCorrelation ID: aaaa0000-bb11-2222-33cc-444444dddddd\r\nTimestamp: 2016-01-09 02:02:12Z",
  "error_codes": [
    70011
  ],
  "timestamp": "YYYY-MM-DD HH:MM:SSZ",
  "trace_id": "0000aaaa-11bb-cccc-dd22-eeeeee333333",
  "correlation_id": "aaaa0000-bb11-2222-33cc-444444dddddd"
}
參數 描述
error 您可用來分類發生的錯誤類型並對錯誤做出反應的錯誤碼字串。
error_description 可協助您識別驗證錯誤根本原因的特定錯誤訊息。
error_codes 可協助進行診斷的 STS 特定錯誤碼清單。
timestamp 錯誤發生時間。
trace_id 可協助進行診斷的要求唯一識別碼。
correlation_id 可協助跨元件進行診斷的要求唯一識別碼。

使用權杖

現在您已取得權杖,可使用權杖對資源提出要求。 當權杖到期時,只要重複執行對 /token 端點的要求,即可取得全新的存取權杖。

GET /v1.0/users HTTP/1.1
Host: graph.microsoft.com:443
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbG...

在終端機中,嘗試下列命令,確保以您自己的方式來取代權杖。

curl -X GET -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbG..." 'https://graph.microsoft.com/v1.0/users'

程式碼範例和其他文件

讀取 Microsoft 驗證程式庫中的用戶端認證概觀文件

範例 平台 描述
active-directory-dotnetcore-daemon-v2 .NET 6.0+ 一個 ASP.NET Core 應用程式,可顯示使用應用程式身分識別來查詢 Microsoft Graph 之租用戶的使用者,而不是代表使用者。 該範例也會說明使用憑證進行驗證的變化。
active-directory-dotnet-daemon-v2 ASP.NET MVC 一個 Web 應用程式,它使用應用程式的身分識別同步處理 Microsoft Graph 中的資料,而不是代表使用者。
ms-identity-javascript-nodejs-console Node.js 主控台 一個 Node.js 應用程式,可顯示使用應用程式身分識別來查詢 Microsoft Graph 之租用戶的使用者