在 Azure App Service 驗證中使用使用者身分識別
本文說明使用 App Service 中內建的驗證和授權時,如何使用使用者身分識別。
在應用程式程式碼中存取使用者宣告
針對所有語言架構,App Service 會藉由將宣告插入要求標頭,讓傳入權杖中的宣告 (無論是否來自已驗證的使用者或用戶端應用程式) 可供您的程式碼使用。 外部要求不被允許設定這些標頭,因此僅在由 App Service 設定時,這些標頭才會出現。 某些範例標頭包括︰
標頭 | 描述 |
---|---|
X-MS-CLIENT-PRINCIPAL |
可用宣告的 Base64 編碼 JSON 表示法。 如需詳細資訊,請參閱解碼用戶端主體標頭。 |
X-MS-CLIENT-PRINCIPAL-ID |
識別提供者所設定呼叫者的識別碼。 |
X-MS-CLIENT-PRINCIPAL-NAME |
識別提供者所設定呼叫者的人類可讀名稱,例如電子郵件地址或使用者主體名稱。 |
X-MS-CLIENT-PRINCIPAL-IDP |
App Service 驗證所使用識別提供者的名稱。 |
提供者權杖也會透過類似的標頭公開。 例如,Microsoft Entra 也會適當地設定 X-MS-TOKEN-AAD-ACCESS-TOKEN
和 X-MS-TOKEN-AAD-ID-TOKEN
。
注意
這些應用程式程式碼的標題可能會因不同的語言架構,而以不同的格式呈現,例如小寫或標題字體。
以任何語言或架構撰寫的程式碼可以從這些標頭中取得所需的資訊。 解碼用戶端主體標頭涵蓋此程序。 針對某些架構,平台也提供可能更方便的額外選項。
解碼用戶端主體標頭
X-MS-CLIENT-PRINCIPAL
包含一組完整的可用宣告,作為 Base64 編碼的 JSON。 這些宣告會經過預設的宣告對應程序,因此有些宣告的名稱可能會與您直接處理權杖時看到的名稱不同。 解碼的承載的結構如下:
{
"auth_typ": "",
"claims": [
{
"typ": "",
"val": ""
}
],
"name_typ": "",
"role_typ": ""
}
屬性 | 類型 | 描述 |
---|---|---|
auth_typ |
string | App Service 驗證所使用識別提供者的名稱。 |
claims |
物件陣列 | 物件的陣列,表示可用的宣告。 每個物件都包含 typ 和 val 屬性。 |
typ |
string | 宣告的名稱。 其可能受限於預設宣告對應,而且可能與權杖中包含的對應宣告不同。 |
val |
字串 | 宣告的值。 |
name_typ |
string | 名稱宣告類型,通常是在定義宣告時提供 name 宣告配置資訊的 URI。 |
role_typ |
string | 角色宣告類型,通常是在定義宣告時提供 role 宣告配置資訊的 URI。 |
若要處理此標頭,您的應用程式必須解碼承載並逐一查看 claims
陣列,以尋找感興趣的宣告。 將這些項目轉換成應用程式語言架構所使用的表示法可能很方便。 以下是 C# 中此程序的範例,其會建構 ClaimsPrincipal 類型供應用程式使用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Http;
public static class ClaimsPrincipalParser
{
private class ClientPrincipalClaim
{
[JsonPropertyName("typ")]
public string Type { get; set; }
[JsonPropertyName("val")]
public string Value { get; set; }
}
private class ClientPrincipal
{
[JsonPropertyName("auth_typ")]
public string IdentityProvider { get; set; }
[JsonPropertyName("name_typ")]
public string NameClaimType { get; set; }
[JsonPropertyName("role_typ")]
public string RoleClaimType { get; set; }
[JsonPropertyName("claims")]
public IEnumerable<ClientPrincipalClaim> Claims { get; set; }
}
public static ClaimsPrincipal Parse(HttpRequest req)
{
var principal = new ClientPrincipal();
if (req.Headers.TryGetValue("x-ms-client-principal", out var header))
{
var data = header[0];
var decoded = Convert.FromBase64String(data);
var json = Encoding.UTF8.GetString(decoded);
principal = JsonSerializer.Deserialize<ClientPrincipal>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
/**
* At this point, the code can iterate through `principal.Claims` to
* check claims as part of validation. Alternatively, we can convert
* it into a standard object with which to perform those checks later
* in the request pipeline. That object can also be leveraged for
* associating user data, etc. The rest of this function performs such
* a conversion to create a `ClaimsPrincipal` as might be used in
* other .NET code.
*/
var identity = new ClaimsIdentity(principal.IdentityProvider, principal.NameClaimType, principal.RoleClaimType);
identity.AddClaims(principal.Claims.Select(c => new Claim(c.Type, c.Value)));
return new ClaimsPrincipal(identity);
}
}
架構特定替代方案
在 ASP.NET 4.6 應用程式中,App Service 會使用已驗證的使用者宣告填入 ClaimsPrincipal.Current,因此您可以遵循標準的 .NET 程式碼模式,包括 [Authorize]
屬性。 同樣地,在 PHP 應用程式中,App Service 會填入 _SERVER['REMOTE_USER']
變數。 針對 Java 應用程式,宣告可從 Tomcat servlet 存取。
對於 Azure Functions,ClaimsPrincipal.Current
未針對 .NET 程式碼填入,但您仍可以在要求標頭中找到使用者宣告,或從要求內容或甚至透過繫結參數取得 ClaimsPrincipal
物件。 如需詳細資訊,請參閱在 Azure Functions 中使用用戶端身分識別。
針對 .NET Core,Microsoft.Identity.Web 支援為目前的使用者填入 App Service 驗證。 若要深入了解,您可以在 Microsoft.Identity.Web Wiki 上閱讀相關資訊,或查看存取 Microsoft Graph 的 Web 應用程式的此教學課程中的示範。
注意
為了讓宣告對應運作,您必須啟用權杖存放區。
使用 API 存取使用者宣告
如果為您的應用程式啟用權杖存放區,則也可以呼叫 /.auth/me
來取得已驗證使用者的其他詳細資料。