Azure App Service 認証でユーザー ID を操作する

この記事では、App Service の組み込みの認証と承認を使用しているときにユーザー ID を操作する方法について説明します。

アプリ コードでユーザー クレームにアクセスする

すべての言語フレームワークにおいて、App Service は、受信トークン (認証されたエンド ユーザーまたはクライアント アプリケーションからなど) 内のクレームを要求ヘッダーに挿入することにより、コードで使用できるようにします。 外部要求ではこれらのヘッダーの設定が許可されないので、これらのヘッダーは App Service によって設定されている場合にのみ存在します。 いくつかのヘッダーの例は次のとおりです。

Header 説明
X-MS-CLIENT-PRINCIPAL 使用可能な要求の Base64 エンコード JSON 表現。 詳細については、「クライアント プリンシパル ヘッダーのデコード」を参照してください。
X-MS-CLIENT-PRINCIPAL-ID ID プロバイダーによって設定された呼び出し元の識別子。
X-MS-CLIENT-PRINCIPAL-NAME ID プロバイダーによって設定された呼び出し元の人間が判読できる名前 (メール アドレス、ユーザー プリンシパル名など)。
X-MS-CLIENT-PRINCIPAL-IDP App Service 認証で使用される ID プロバイダーの名前。

プロバイダー トークンも同様のヘッダーを使って公開されます。 たとえば、X-MS-TOKEN-AAD-ACCESS-TOKENX-MS-TOKEN-AAD-ID-TOKEN も必要に応じて Microsoft ID プロバイダーで設定されます。

Note

これらのヘッダーは、さまざまな言語フレームワークによって異なる形式 (小文字や先頭文字が大文字など) でアプリ コードに提供される可能性があります。

任意の言語またはフレームワークで記述されたコードで、これらのヘッダーから必要な情報を取得できます。 このプロセスについては、「クライアント プリンシパル ヘッダーのデコード」で説明します。 一部のフレームワークでは、さらに便利な追加オプションもプラットフォームに用意されています。

クライアント プリンシパル ヘッダーのデコード

X-MS-CLIENT-PRINCIPAL には、使用可能なすべての要求が Base64 エンコード JSON として含まれています。 これらの要求は既定の要求マッピング プロセスで処理されるため、トークンを直接処理する場合に表示される名前とは異なる可能性があります。 デコードされたペイロードは、次のように構成されます。

{
    "auth_typ": "",
    "claims": [
        {
            "typ": "",
            "val": ""
        }
    ],
    "name_typ": "",
    "role_typ": ""
}
プロパティ タイプ Description
auth_typ string App Service 認証で使用される ID プロバイダーの名前。
claims オブジェクトの配列 使用可能な要求を表すオブジェクトの配列。 各オブジェクトには、typ および val プロパティが含まれています。
typ string 要求の名前。 これは既定の要求マッピングの対象になっている可能性があり、トークンに含まれている対応する要求とは異なる場合があります。
val string クレームの値。
name_typ string 名前要求の種類。これは通常、name 要求 (定義されている場合) に関するスキーム情報を提供する URI です。
role_typ string ロール要求の種類。これは通常、role 要求 (定義されている場合) に関するスキーム情報を提供する URI です。

このヘッダーを処理するには、アプリでペイロードをデコードし、claims 配列を反復処理して目的の要求を見つける必要があります。 これらをアプリの言語フレームワークで使用される表現に変換すると、処理しやすくなる場合があります。 アプリで使用する ClaimsPrincipal 型を構成する C# でのこのプロセスの例を、次に示します。

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 サーブレットからアクセスできます

Azure Functions では、.NET コードの ClaimsPrincipal.Current は設定されていませんが、要求ヘッダーでユーザーの要求を検索することも、要求コンテキストまたはバインディング パラメーターを使用して ClaimsPrincipal オブジェクトを取得することもできます。 詳細については、Azure Functions でのクライアント ID の操作に関するセクションを参照してください。

.NET Core の場合、Microsoft.Identity.Web では、現在のユーザーへの App Service 認証の設定がサポートされています。 詳細については、、Microsoft.Identity.Web の Wiki を参照するか、Microsoft Graph にアクセスする Web アプリに関するこちらのチュートリアルを参照してください。

注意

要求のマッピングを機能させるには、トークン ストアを有効にする必要があります。

API を使用してユーザー クレームにアクセスする

アプリでトークン ストアが有効になっている場合は、/.auth/me を呼び出して認証されたユーザーの他の詳細を取得することもできます。

次のステップ