Microsoft身分識別平臺和 OAuth 2.0 用戶端認證流程
OAuth 2.0 用戶端認證授與流程允許 Web 服務(機密用戶端)使用自己的認證,而不是模擬使用者,以在呼叫另一個 Web 服務時進行驗證。 RFC 6749中指定的授權類型,有時稱為 雙腿 OAuth,可用來使用應用程式的身分識別來存取網路託管的資源。 此類型通常用於必須在背景中執行的伺服器對伺服器互動,而不需與使用者立即互動,而且通常稱為 精靈 或 服務帳戶。
在客戶端認證流程中,許可權會由系統管理員直接授與應用程式本身。 當應用程式向資源呈現令牌時,資源會強制應用程式本身具有執行動作的授權,因為沒有任何使用者參與驗證。 本文涵蓋下列兩個步驟:
- 授權應用程式呼叫 API
- 如何取得呼叫該 API所需的令牌。
本文說明如何直接針對應用程式中的通訊協議進行程序設計。 可能的話,建議您改用支援的 Microsoft 驗證連結庫 (MSAL) 來 取得令牌,並呼叫受保護的 Web API。 您也可以參考使用 MSAL的 client_id
和 client_secret
(這些是取得重新整理令牌所需的)可以用來改為取得存取令牌。
為了獲得更高的保證層級,Microsoft身分識別平臺也允許呼叫服務使用 憑證進行驗證, 或同盟認證,而不是共享密碼。 由於正在使用應用程式自己的認證,因此這些認證必須保持安全。 永不 在原始程式碼中發佈該認證、將其內嵌在網頁中,或將其用於廣泛散發的原生應用程式中。
通訊協議圖表
整個客戶端認證流程看起來類似下圖。 本文稍後會說明每個步驟。
取得直接授權
應用程式通常會以下列兩種方式之一接收直接授權來存取資源:
- 透過資源 的存取控制清單 (ACL)
- 透過在 Microsoft Entra ID 中指派應用程式許可權
這兩種方法在 Microsoft Entra ID 中最為常見,我們建議它們用於執行客戶端認證流程的客戶端和資源。 資源也可以選擇以其他方式授權其用戶端。 每個資源伺服器都可以選擇最適合其應用程式的方法。
訪問控制清單
資源提供者可能會根據它知道的應用程式 (用戶端) 識別符清單強制執行授權檢查,並授與特定層級的存取權。 當資源從 Microsoft 身分識別平台接收令牌時,它可以解碼令牌,並從 appid
和 iss
聲明中提取用戶端應用程式 ID。 然後,它會將應用程式與它所維護的訪問控制清單 (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 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
專業提示:請嘗試在瀏覽器中貼上下列要求。
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 Token),您必須使用您註冊為應用程式認證的憑證來建立和簽署。 請參閱 憑證的認證,以瞭解如何註冊您的憑證和聲明格式。 |
grant_type |
必填 | 必須設定為 client_credentials 。 |
憑證型要求的參數與共享密碼型要求只有一種方式不同:client_secret
參數會由 client_assertion_type
和 client_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 來顯示租戶的使用者 |