ASP.NET アプリケーションでAzure Active Directory (Azure AD) で認証する - ASP.NET Core

ASP.NET アプリケーションでAzure Active Directory (Azure AD) で認証するコードを紹介します。

概要

こちらの記事では、 アプリケーションで管理しているアカウントで認証するASP.NET アプリケーションのコードを紹介しました。
アプリケーションの数が増えてくるなどすると、用途によっては、アプリケーションでのアカウント管理をしたくない場合があります。 アカウント管理には、Googleアカウント、Microsoft アカウント、Active Directoryアカウントなどいくつかの方法がありますが、 今回は、Azure Active Directory (Azure AD)のアカウントを利用して、ASP.NETアプリケーションにサインインする方法を紹介します。

実装の方針

Azure Active Directory (Azure AD)で認証するライブラリとして、Microsoft.Identity.Web, Microsoft,Identity.Web.UI を利用しますが、Microsoft.Identity.Web.UI ではサインイン、サインアウトの処理がMVCコントローラーとして実装されています。 アプリケーション自体はRazorPageで実装していますが、サインイン、サインアウト処理でMVCコントローラーを利用する方式となっており、 Program.csでは、MVCコントローラーへのマッピングの実装があります。

プログラム

ASP.NET Coreアプリケーションを作成します。

パッケージ

Microsoft.Identity.Web パッケージと Microsoft,Identity.Web.UI パッケージをインストールします。

コマンドは以下になります。
Install-Package Microsoft.Identity.Web -Version (インストールするバージョン)
Install-Package Microsoft.Identity.Web.UI -Version (インストールするバージョン)
インストール手順はNuGetパッケージマネージャーコンソールの場合はこちらの記事、 GUIのパッケージ管理の場合はこちらの記事を参照してください。

ファイル構成

ファイル構成は次の通りです。

コード

以下のコードを記述します。
/Pages/Index.cshtml
@page
@model AuthenticationAzureADSimpleSigninSignout.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 AuthenticationAzureADSimpleSigninSignout.Pages
{
  [AllowAnonymous]
  public class IndexModel : PageModel
  {
    public void OnGet()
    {
    }
  }
}
/Pages/Content.cshtml
@page
@model AuthenticationAzureADSimpleSigninSignout.Pages.ContentModel
@{
}
<html>
  <head>

  </head>
  <body>
    <h1>コンテンツのページ</h1>
    <p>コンテンツのページです</p>
    <p>認証が必要なページです</p>
  </body>
</html>
/Pages/Content.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authorization;

namespace AuthenticationAzureADSimpleSigninSignout.Pages
{
  [Authorize]
  public class ContentModel : PageModel
  {
    public void OnGet()
    {
    }
  }
}
Program.cs
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd");
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.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.Run();

アプリケーションのAzure ADへの登録

プロジェクトをビルドして実行します。appsettings.jsonが設定できていないため、実行するとエラーが発生します。
デバッグ実行時のURLをメモします。今回の場合は 'https://localhost:7200' となります。

Azure Adにアプリケーションを登録します。
アプリケーション登録時に、[リダイレクト URI]のURLに次のURLを設定します。
https://(デバッグ実行時のアプリケーションルートURL)(appsettings.jsonの"CallbackPath"に設定したパス)

今回の例の場合は次の値になります。
https://localhost:7200/signin-oidc

また、[フロントチャネルのログアウトURI]には次のURLを設定します。
https://(デバッグ実行時のアプリケーションルートURL)(appsettings.jsonの"SignedOutCallbackPath"に設定したパス)

今回の例の場合は次の値になります。
https://localhost:7200/signout-oidc
Azure ADへのアプリケーション登録の操作手順はこちらの記事を参照してください。
登録したアプリケーションの、クライアントIDとテナントIDを確認します。

appsettings.jsonの設定

Azure ADのアプリケーション登録情報を参照して、appsettings.jsonファイルを編集します。
appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },

  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "(ドメイン)",
    "ClientId": "(クライアントID)",
    "TenantId": "(テナントID)",
    "ClientCertificates": [
    ],
    "CallbackPath": "/signin-oidc",
    "SignedOutCallbackPath ": "/signout-oidc"
  },
  "AllowedHosts": "*"
}

解説

/Pages/Index.cshtml /Pages/Index.cshtml.cs

認証が不要なページとするため、ページモデルクラスに [AllowAnonymous] 属性を記述しています。
[Sign In] [Sign Out] [content] の3つのリンクを配置しています。[Sign In] [Sign Out]はMicrosoft,Identity.Web.UIのコントローラーを呼び出す設定になっており、asp-area, asp-controller, asp-action の属性を設定しています。

/Pages/Content.cshtml /Pages/Content.cshtml.cs

認証を必要とするページとして実装しています。ページモデルクラスに [Authorize] 属性を記述しています。

Program.cs

Azure ADの認証に関する設定部分です。
AddMicrosoftIdentityWebAppAuthenticationでAppsettings.jsonの設定を読み込みます。第一引数に IConfigurationオブジェクトを与え、第二引数にJSONファイルのセクション名を与えます。今回、appsettings.jsonファイルの"AzureAd"セクションに設定を記述しているため、"AzureAd"の文字列を与えています。

AddRazorPages()メソッドは通常のRazorPagesアプリケーションでも呼び出しますが、今回は、MVCコントローラーのルーティングがあるため、 AddMvcOptionsも追加しています。
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd");
builder.Services.AddRazorPages().AddMvcOptions(options => {
  var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
  options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();

認証に関する機能を利用するため、UseAuthentication() UseAuthorization() を追加します。 サインイン、サインアウトでは、MVCコントローラーへのルーティングもあるため、MapControllers()も追加します。
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.Run();

実行結果

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


リンクをクリックするとMicrosoftアカウントの認証画面が表示されます。
サインインするアカウントを選択するか[別のアカウントを使用する]をクリックして、Micrsoftアカウントを入力します。


初回のサインイン時には下図のアプリケーション許可のダイアログが表示されます。[承諾]ボタンをクリックして アプリケーションのアクセス許可を承認します。


サインインができると元のページに戻ります。[Sign In]リンクからサインインした場合は、アプリケーションルートの画面に戻り、 [Content]リンクからサインインした場合は、コンテンツのページが表示されます。 アカウント認証ができたため、コンテンツのページが表示できています。


アプリケーションルートのページに戻り[Sign Out]のリンクをクリックします。下図のサインアウトの画面が表示されます。
サインアウトするアカウントをクリックします。


サインアウト処理が実行されます。


サインアウトが完了すると、アプリケーションの(アプリケーションルートURL)/MicrosoftIdentity/Account/SignedOut にリダイレクトされます。


非常にシンプルなAzureAD アカウントでのサインイン、サインアウトのアプリケーションを実装できました。

補足:まったく関係のないMicrosoftアカウントでサインインするとどうなるか?

今回実装したプログラムで、Azure ADと全く関係のないMicrosoftアカウントでサインインするとどうなるか動作を確認してみます。
サインイン画面で[別のアカウントを使用する]の項目をクリックします。


[サインイン]画面が表示されます。


"outlook.jp" のMicrosoftアカウントを入力します。


このアカウントでは、サインインの確認(2要素認証)が動作します。


Microsoft Authenticator アプリで認証します。


セキュリティ情報の確認のありますので[問題ありません]ボタンをクリックします。


サインイン状態の保持の確認もあります。


認証はできましたが次のエラーが発生します。
テナントのAzure ADに所属していないMicrosoftアカウントでは認証できないエラーメッセージが表示されます。 アプリケーションを利用できるようにするためには、このMicrsofotアカウントをAzure ADにゲスト登録するなどの対応が必要です。
Azure ADへのゲスト登録の手順はこちらの記事を参照してください。
エラーメッセージ
AADSTS50020: User account '(サインインしたMicrosoftアカウント)' from identity provider '(プロバイダ名)' does not exist in tenant
'(アプリのテナント名)' and cannot access the application '(アプリケーションID)'(アプリケーション名) in that tenant.
The account needs to be added as an external user in the tenant first. Sing out and sign in again with a different Azure Active Directory user account.


なお、テナントのAzure ADに登録せずにMicrosoftアカウントでの認証をしたい場合は、"Azure Active Directory B2C (Azure AD B2C)" を利用すると実装可能です。

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