ASP.NETアプリケーションでサインインした Azure Active Directory (Azure AD) のユーザー情報を取得する

ASP.NETアプリケーションでサインインした Azure Active Directory (Azure AD) のユーザー情報を取得するコードを紹介します。

概要

こちらの記事では ASP.NET Coreアプリケーションで、 Azure Active Directory (Azure AD)のアカウントでサインインするプログラムを紹介しました。 紹介したプログラムはサインイン、サインアウトのみを実行するプログラムのため、サインインできた場合に、サインインしたユーザーの情報や プロフィールのアイコン画像を取得したいです。
この記事では、Azure ADでアプリケーションにサインインし、サインインしたユーザーの情報を取得してページに表示するコードを紹介します。

プログラム

ASP.NET Coreアプリケーションを作成します。 認証の基本部分はこちらの記事で紹介しているコードを利用します。

事前準備

Azure ポータルの Azure Active Directoryの設定画面で、アプリケーションの登録をします。手順はこちらの記事を参照してください。
今回のプログラムではMicrosoft GraphのAPIを呼び出すため、アプリケーションの登録後にクライアントシークレットを作成します。 手順はこちらの記事を参照してください。

パッケージのインストール

パッケージをインストールします。
  • Microsoft.Identity.Web
  • Microsoft.Identity.Web.UI
  • Microsoft.Identity.Web.MicrosoftGraph
の3つをインストールします。

ファイル構成

以下のファイル構成です。

コード

以下のファイル、コードを作成します。
/Pages/Index.cshtml
@page
@model AuthenticationAzureADGetUserinfo.Pages.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
}
<html>
  <head></head>
  <body>
    <h1>index</h1>
    <a asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Sign In</a><br/>
    <a asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignOut">Sign Out</a><br/>
    <a asp-page="/Content">Content</a><br/>
  </body>
</html>
/Pages/Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authorization;

namespace AuthenticationAzureADGetUserinfo.Pages
{
  [AllowAnonymous]
  public class IndexModel : PageModel
  {
    public void OnGet()
    {
    }
  }
}
/Pages/Content.cshtml
@page
@model AuthenticationAzureADGetUserinfo.Pages.ContentModel
@{
}
<html>
  <head>

  </head>
  <body>
    <h1>コンテンツのページ</h1>
    <p>ID:@Model.ID</p>
    <p>アカウント名:@Model.Name</p>
    <p>名前:@Model.GivenName</p>
    <p>Mail:@Model.Mail</p>
    <img src="data:image/jpeg;base64, @Model.Image" />
    <p>コンテンツのページです</p>
    <p>認証が必要なページです</p>
  </body>
</html>
/Pages/Content.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Graph;

namespace AuthenticationAzureADGetUserinfo.Pages
{
  [Authorize]
  public class ContentModel : PageModel
  {
    private readonly GraphServiceClient _graphServiceClient;

    public string ID { get; set; }
    public string Name { get; set; }
    public string GivenName { get; set; }
    public string Mail { get; set; }
    public string Image { get; set; }

    public ContentModel(GraphServiceClient graphServiceClient)
    {
      _graphServiceClient = graphServiceClient;
    }

    public void OnGet()
    {
      User user = _graphServiceClient.Me.Request().GetAsync().Result;
      ID = user.Id;
      Name = user.DisplayName;
      GivenName = user.GivenName;
      Mail = user.Mail;

      Stream s = _graphServiceClient.Me.Photo.Content.Request().GetAsync().Result;
      byte[] photoByte = ((MemoryStream)s).ToArray();
      Image = Convert.ToBase64String(photoByte);
    }

  }
}
Program.cs
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;

var builder = Microsoft.AspNetCore.Builder.WebApplication.CreateBuilder(args);

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
  .EnableTokenAcquisitionToCallDownstreamApi()
  .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
  .AddSessionTokenCaches();


builder.Services.AddRazorPages().AddMvcOptions(options => {
  var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
  options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();

var app = builder.Build();

app.UseRouting();
app.UseSession();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.MapRazorPages();
app.Run();
appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "ipentec.com",
    "ClientId": "(クライアントID)",
    "TenantId": "(テナントID)",
    "ClientSecret": "(クライアントシークレット)",
    "ClientCertificates": [
    ],
    "CallbackPath": "/signin-oidc",
    "SignedOutCallbackPath ": "/signout-oidc"
  },
  "DownstreamApi": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": "user.read"
  },
  "AllowedHosts": "*"
}

解説

Azure ADでのサインイン、サインアウトに関してはこちらの記事を参照してください。

Program.cs

今回、サインインしたユーザーの情報はMicrosoft Graphを利用して取得しますので、AddMicrosoftGraph を追加しています。
Microsoft Graphの設定は、appsettings.json の"DownstreamApi" のセクションに記述していますので、AddMicrosoftGraph()メソッドの引数に builder.Configuration.GetSection("DownstreamApi") を与えています。
また、トークンのキャッシュを保持する必要がありますが、今回は、AddSessionTokenCaches() を呼び出し、セッションにキャッシュを保存する方式を利用します。
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
  .EnableTokenAcquisitionToCallDownstreamApi()
  .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
  .AddSessionTokenCaches();

セッションの機能を利用するため、app.UseSession(); を追加しています。
app.UseRouting();
app.UseSession();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.MapRazorPages();
app.Run();

Content.cshtml.cs / Content.cshtml

コンストラクタでは、Microsoft GraphのAPIにアクセスできるように、GraphServiceClient をインジェクションにより取得します。 取得したクライアントは、_graphServiceClient プロパティに格納します。
    public ContentModel(GraphServiceClient graphServiceClient)
    {
      _graphServiceClient = graphServiceClient;
    }

OnGetメソッドでページ表示時にサインインしているユーザーの情報を取得します。
_graphServiceClient.Me.Request().GetAsync().Result により、ユーザー情報が格納された、Microsoft.Graph.Userオブジェクトが取得できます。 Userオブジェクトのプロパティを参照して、IDや表示名、メールアドレスを取得できます。

プロフィール画像は、_graphServiceClient.Me.Photo.Content.Request().GetAsync().Result により画像のストリームを取得できますので、byte配列で読み出したのち、 Base64エンコードして、文字列の形式で保持します。
public void OnGet()
{
  User user = _graphServiceClient.Me.Request().GetAsync().Result;
  ID = user.Id;
  Name = user.DisplayName;
  GivenName = user.GivenName;
  Mail = user.Mail;

  Stream s = _graphServiceClient.Me.Photo.Content.Request().GetAsync().Result;
  byte[] photoByte = ((MemoryStream)s).ToArray();
  Image = Convert.ToBase64String(photoByte);
}

RazorPageでは、モデルクラスのプロパティの値を参照して画面にサインインしたユーザーの情報を表示します。 画像はファイルとして保持していないため、sec属性に data:image/jpeg;base64, を指定し、Base64エンコードされた画像のデータの文字列をページに直接埋め込んでいます。
    <h1>コンテンツのページ</h1>
    <p>ID:@Model.ID</p>
    <p>アカウント名:@Model.Name</p>
    <p>名前:@Model.GivenName</p>
    <p>Mail:@Model.Mail</p>
    <img src="data:image/jpeg;base64, @Model.Image" />
    <p>コンテンツのページです</p>
    <p>認証が必要なページです</p>

Microsoft Graph APIの許可設定

Microsoft Graph APIの許可設定をする必要があります。
設定手順はこちらの記事を参照してください。

実行結果

プロジェクトを実行し、アプリケーションルートのURLにアクセスします。下図のページが表示されます。
[Sign In]または[Content]のリンクをクリックします。


クリックすると、下図のMicrosoft アカウントの認証画面が表示されます。Azure ADに登録されているユーザーで認証します。


今回は[別のアカウントを使用する]をクリックし、一覧にないアカウントで認証します。サインイン画面が表示されます。 Azure ADに登録されているユーザーのメールアドレスを入力します。


パスワードを入力します。


[Content]リンクから認証した場合は、下図のコンテンツのページが表示されます。 [Sign In]リンクから認証した場合はアプリケーションルートの画面に戻りますので、[Content]リンクをクリックします。 下図のページが表示されます。Azure ADのユーザー情報に設定されている、ユーザーのID、アカウント名、表示名、メールアドレス、プロフィールの画像が表示されます。


Auzre ADのユーザーで認証し、サインインしたユーザーの情報を取得できました。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2022-10-28
作成日: 2022-08-08
iPentec all rights reserverd.