宣告挑戰、宣告要求和用戶端功能

宣告挑戰 是從 API 傳送的回應,指出用戶端應用程式傳送的存取權杖沒有足夠的宣告。 這可能是因為權杖無法滿足針對該 API 所設定的條件式存取原則,或已撤銷存取權杖。

用戶端應用程式會提出 宣告要求 ,以將使用者重新導向回身分識別提供者,以利用宣告來取得新的權杖,以滿足不符合的其他需求。

使用增強式安全性功能的應用程式(例如 持續存取評估 (CAE) 條件式存取驗證內容 )必須做好準備,才能處理宣告的挑戰。

當您的應用程式在其對服務的呼叫中宣告其用戶端功能時,您的應用程式將會收到來自熱門服務的宣告挑戰,例如Microsoft Graph

宣告挑戰標頭格式

宣告挑戰是一個指示詞 www-authenticate ,它是由 API 傳回的標頭(當 存取權杖 未獲授權時),而且需要具有正確功能的新存取權杖。 宣告挑戰包含多個部分:回應的 HTTP 狀態碼和 www-authenticate 標頭,其本身具有多個部分,而且必須包含宣告指示詞。

以下是範例:

HTTP 401; Unauthorized

www-authenticate =Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", error="insufficient_claims", claims="eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlIjoiYzEifX19"

HTTP 狀態碼:必須是 401 未經授權

www-驗證回應標頭, 包含:

參數 必要條件/選擇性 描述
驗證類型 必要 必須是 持有人。
Realm 選用 租使用者識別碼或租使用者功能變數名稱 (例如,正在存取 microsoft.com) 。 在驗證通過 通用端點的情況下,必須是空字串。
authorization_uri 必要 授權端點的 URI,可在必要時執行互動式驗證。 如果是在領域中指定,租使用者資訊必須包含在 authorization_uri 中。 如果 realm 是空字串,則 authorization_uri 必須針對 通用端點
error 必要 若應產生宣告挑戰,則必須是「insufficient_claims」。
claims 當 error 為 "insufficient_claims" 時,則為必要項。 以引號括住的字串,其中包含 base 64 編碼的 宣告要求。 宣告要求應要求 JSON 物件最上層 "access_token" 的宣告。 要求的 (宣告值) 將會相依于內容,並于本檔稍後指定。 基於大小考慮,信賴憑證者應用程式應該在基底64編碼之前縮短 JSON。 上述範例的原始 JSON 為 {"access_token": {"acr": {"必要": true,"value": "cp1"}}}。

401 回應可能包含一個以上的 www-authenticate 標頭。 上表中的所有欄位都必須包含在相同的 www-authenticate 標頭中。 www-authenticate包含宣告挑戰的標頭 可以 包含其他欄位。 標頭中的欄位未排序。 根據 RFC 7235,每個參數名稱都必須在每個驗證配置挑戰中只出現一次。

宣告要求

當應用程式收到宣告挑戰時,會指出先前的存取權杖不再被視為有效。 在此案例中,應用程式應該從任何本機快取或使用者會話清除權杖。 然後,它應該將已登入的使用者重新導向回到 Azure Active Directory (Azure AD) 使用 OAuth 2.0 授權碼流程 搭配 宣告 參數來取得新的權杖,以滿足不符合的其他需求。

以下是範例:

GET https://login.microsoftonline.com/14c2f153-90a7-4689-9db7-9543bf084dad/oauth2/v2.0/authorize
?client_id=2810aca2-a927-4d26-8bca-5b32c1ef5ea9
&redirect_uri=https%3A%2F%contoso.com%3A44321%2Fsignin-oidc
&response_type=code
&scope=openid%20profile%20offline_access%20user.read%20Sites.Read.All
&response_mode=form_post
&login_hint=kalyan%ccontoso.onmicrosoft.com
&domain_hint=organizations
claims=%7B%22access_token%22%3A%7B%22acrs%22%3A%7B%22essential%22%3Atrue%2C%22value%22%3A%22c1%22%7D%7D%7D

宣告挑戰應該在 /authorize 端點的所有 Azure AD 呼叫中傳遞,直到成功抓取權杖為止,之後不再需要權杖。

若要填入宣告參數,開發人員必須:

  1. 解碼先前收到的 base64 字串。
  2. URL 將字串編碼,並再次新增至 宣告 參數。

完成此流程之後,應用程式將會收到具有其他宣告的存取權杖,以證明使用者滿足所需的條件。

用戶端功能

用戶端功能可協助資源提供者(例如 Web API)偵測呼叫的用戶端應用程式是否瞭解宣告的挑戰,並可據以自訂回應。 如果並非所有 API 用戶端都能夠處理宣告挑戰,但某些較舊的版本仍預期不同的回應,這項功能可能會很有用。

某些熱門的應用程式(例如 Microsoft Graph )只會在呼叫用戶端應用程式宣告它能夠使用 用戶端功能 來處理時,才會傳送宣告挑戰。

為了避免額外的流量或對使用者體驗的影響,Azure AD 不會假設您的應用程式可以處理宣告的挑戰,除非您明確加入宣告。 應用程式將不會收到宣告挑戰 (而且將無法使用相關的功能,例如 CAE 權杖) 除非它宣告它已準備好使用 "cp1" 功能來處理它們。

如何將用戶端功能傳達給 Azure AD

下列範例宣告參數顯示用戶端應用程式如何將其功能傳達給 OAuth 2.0 授權碼流程中的 Azure AD。

Claims: {"access_token":{"xms_cc":{"values":["cp1"]}}}

使用 MSAL 程式庫的那些程式碼將會使用下列程式碼:

_clientApp = PublicClientApplicationBuilder.Create(App.ClientId)
 .WithDefaultRedirectUri()
 .WithAuthority(authority)
 .WithClientCapabilities(new [] {"cp1"})
 .Build();*

使用 Web.config 的人員可以將下列程式碼新增至設定檔:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    // the remaining settings
    // ... 
    "ClientCapabilities": [ "cp1" ]
},

Azure AD 的要求看起來會像這樣的範例:

GET https://login.microsoftonline.com/14c2f153-90a7-4689-9db7-9543bf084dad/oauth2/v2.0/authorize
?client_id=2810aca2-a927-4d26-8bca-5b32c1ef5ea9
&redirect_uri=https%3A%2F%contoso.com%3A44321%2Fsignin-oidc
&response_type=code
&scope=openid%20profile%20offline_access%20user.read%20Sites.Read.All
&response_mode=form_post
&login_hint=kalyan%ccontoso.onmicrosoft.com
&domain_hint=organizations
&claims=%7B%22access_token%22%3A%7B%22xms_cc%22%3A%7B%22values%22%3A%5B%22cp1%22%5D%7D%7D%7D

當您已經有宣告參數的現有承載時,您會將它新增至現有的集合。

例如,如果您已經有來自條件存取驗證內容作業的下列回應

{"access_token":{"acrs":{"essential":true,"value":"c25"}}}

您會在現有的 宣告 承載中預先加上用戶端功能。

{"access_token":{"xms_cc":{"values":["cp1"]},"acrs":{"essential":true,"value":"c25"}}}

在存取權杖中接收 xms_cc 宣告

若要接收用戶端應用程式是否可以處理宣告挑戰的相關資訊,API 實作者必須要求 xms_cc 作為其應用程式資訊清單中的選擇性宣告。

存取權杖中值為 "cp1" 的 xms_cc 宣告,是識別用戶端應用程式是否能夠處理宣告挑戰的授權方式。 xms_cc 是選擇性的宣告,將不會一律在存取權杖中發出,即使用戶端以 "xms_cc" 傳送宣告要求也是一樣。 為了讓存取權杖包含 xms_cc 宣告,資源應用程式 (也就是說,API 實作者) 必須在其應用程式資訊清單中要求 xms_cc 做為 選擇性 宣告。 當要求為選擇性宣告時,只有在用戶端應用程式傳送宣告要求中的 xms_cc 時,才會將 xms_cc 新增至存取權杖。 Xms_cc 宣告要求的值將會包含在存取權杖中的 xms_cc 宣告值(如果它是已知的值)。 目前唯一已知的值為 cp1

這些值不區分大小寫且未排序。 如果 xms_cc 宣告要求中指定了多個值,這些值就會是多重值的集合,做為 xms_cc 宣告的值。

要求:

{ "access_token": { "xms_cc":{"values":["cp1","foo", "bar"] } }}

將會產生

"xms_cc": ["cp1", "foo", "bar"]

在存取權杖中,如果 cp1foobar 是已知功能。

這是要求 xms_cc 選用 宣告之後,應用程式的資訊清單看起來的樣子

"optionalClaims":
{
    "accessToken": [
    {
        "additionalProperties": [],
        "essential": false,
        "name": "xms_cc",
        "source": null
    }],
    "idToken": [],
    "saml2Token": []
}

然後,API 可以根據用戶端是否能夠處理宣告挑戰來自訂回應。

C 中的範例#

Claim ccClaim = context.User.FindAll(clientCapabilitiesClaim).FirstOrDefault(x => x.Type == "xms_cc");
if (ccClaim != null && ccClaim.Value == "cp1")
{
    // Return formatted claims challenge as this client understands this
}
else
{
    // Throw generic exception
    throw new UnauthorizedAccessException("The caller does not meet the authentication bar to carry our this operation. The service cannot allow this operation");
}

後續步驟