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

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

在用戶端認證流程中,管理員會直接將權限授與應用程式本身。 當應用程式向資源呈現令牌時,資源會強制應用程式本身具有執行動作的授權,因為沒有任何使用者參與驗證。 本文涵蓋下列兩個步驟:

本文說明如何直接針對應用程式中的通訊協議進行程序設計。 建議您盡可能改為使用支援的 Microsoft 驗證程式庫 (MSAL),以取得權杖並呼叫受保護的 Web API。 您也可以參考使用 MSAL範例應用程式。 請注意,重新整理令牌永遠不會使用此流程 client_id 來授與 ,而且 client_secret (取得重新整理令牌時需要用到)可用來改為取得存取令牌。

為了獲得較高層級的保證,Microsoft 身分識別平台 也允許呼叫服務使用憑證或同盟認證進行驗證,而不是共享密碼。 由於正在使用應用程式自己的認證,因此這些認證必須保持安全。 請勿 在原始程式碼中發佈該認證、將其內嵌在網頁中,或將其用於廣泛散發的原生應用程式中。

通訊協定圖表

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

Diagram showing the client credentials flow

取得直接授權

應用程式通常會以下列兩種方式之一接收直接授權來存取資源:

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

存取控制清單

資源提供者可能會根據它知道的應用程式 (用戶端) 識別符清單強制執行授權檢查,並授與特定層級的存取權。 當資源從 Microsoft 身分識別平台 收到令牌時,它可以譯碼令牌,並從 和 iss 宣告擷取用戶端應用程式標識碼appid。 然後,它會將應用程式與它所維護的訪問控制清單 (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 的應用程式必須實作許可權檢查,才能接受令牌。

如果您要防止應用程式取得應用程式無角色應用程式存取令牌, 請確定您的應用程式已啟用指派需求。 這將會封鎖使用者和應用程式,而不需要獲指派的角色就能取得此應用程式的令牌。

應用程式權限

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

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

若要搭配您自己的 API 使用應用程式角色(應用程式許可權),您必須先 在 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=535fb089-9ff3-47b6-9bfb-4f1264799865
&state=12345
&redirect_uri=http://localhost/myapp/permissions

專業提示:請嘗試在瀏覽器中貼上下列要求。

https://login.microsoftonline.com/common/adminconsent?client_id=535fb089-9ff3-47b6-9bfb-4f1264799865&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=a8990e1f-ff32-408a-9f8e-78d3b9139b95&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=535fb089-9ff3-47b6-9bfb-4f1264799865
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret=sampleCredentials
&grant_type=client_credentials
# Replace {tenant} with your tenant!
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=535fb089-9ff3-47b6-9bfb-4f1264799865&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=qWgdYAmab0YSkuL1qKv5bPX&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=97e0a5b7-d745-40b6-94fe-5f77d35c6e05
&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=97e0a5b7-d745-40b6-94fe-5f77d35c6e05
&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 身分識別平台 以外的另一個識別提供者取得的判斷提示(JWT 或 JSON Web 令牌),例如 Kubernetes。 此 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: 255d1aef-8c98-452f-ac51-23d051240864\r\nCorrelation ID: fb3d2015-bc17-4bb9-bb85-30c5cf1aaaa7\r\nTimestamp: 2016-01-09 02:02:12Z",
  "error_codes": [
    70011
  ],
  "timestamp": "YYYY-MM-DD HH:MM:SSZ",
  "trace_id": "255d1aef-8c98-452f-ac51-23d051240864",
  "correlation_id": "fb3d2015-bc17-4bb9-bb85-30c5cf1aaaa7"
}
參數 描述
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 eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...

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

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 來顯示租用戶的使用者