【認証機能】ASP.NET Core と Identity Server を利用し複数のWebアプリケーションで認証機能を提供する

Masahito Morishima Masahito Morishima
Keiichi Hashimoto Keiichi Hashimoto
【認証機能】ASP.NET Core と Identity Server を利用し複数のWebアプリケーションで認証機能を提供する

はじめに

ASP.NET Core では、アプリケーションに認証・認可の機能を提供するための多くのライブラリやサービスが提供されています。

  • ローカルストア(例えばデータベース)を利用した認証
  • Azure Active Directory
  • Azure Active Directory B2C
  • IDプロパイダー(Facebook/Google/Microsoft/Twitter)
  • Identity Server

本トピックは、この中から ASP.NET Core で作成するWebアプリケーション を Identity Server を利用して認証する方法について解説します。

Identity Server とは

簡単に説明すると Identity Server とは、ASP.NET Core 向けの OpenID Connect および OAuth を実装するフレームワークです。これを利用することで簡単に認証サーバーを立ち上げ、Webアプリケーションと連携することができます。

Identity Server4

一つ前の版である、Identity Server4 は以下でフリーソフトウェアとして公開されており、ライセンスの範囲で自由に利用することが可能です。ただし、この版は2022年11月までしかバグ修正とセキュリティアップデートは行われませんので注意が必要です。

Identity Server5 (Duende Identity Server)

新しい Identity Server5 は Duende 社から引き続き提供されますが、ライセンスが変更されています。詳細は、ここ を確認していただくと分りますが、OSS ライセンスと商用ライセンスのデュアルライセンスになります。引き続き開発と評価、一部のスモールビジネスでは無償で利用可能ですが、それ以外の商用利用にはライセンスフィーが必要となります。

Identity Serverを選択する理由

Azure には既に Identity as a Service としてAzure Active Directory B2C が存在しそれを利用することもできます。SaaSであるため運用コストなどの低減のメリットなどもありますが、全てをカスタマイズすることはできません。また用意されているユーザーフローを利用することは簡単ですが、実際にカスタムポリシーを実装するのは難易度も高く、顧客要件の実現可能性について十分検証する必要があります。

Identity Servier では、(初期テンプレートもありますが)それらのフローを実装することで、ほぼ全てをカスタマイズすることができます。画面は Razor テンプレートですし、ロジック部分も ASP.NET Core Identity フレームワークを利用できます。いままでのMVCアプリケーションのように、ノウハウの延長線上にあるため実装コストも見積もりやすいでしょう。もちろん、コードの保守やデータのバックアップなどの運用コストを増加させる要因もありますが、それらはAzureの機能を利用することで低減できるでしょう。

Identity Server を利用した認証サーバーの実装

Identity Server 自身も ASP.NET Core アプリケーションとして実装されており、そのひな形は dotnet コマンドで作成します。テンプレートをインストールするといくつかの種類のひな形プロジェクトを作成可能になります。

$ dotnet new --install Duende.IdentityServer.Templates
$ dotnet new 
Duende IdentityServer with ASP.NET Core Identity           isaspid             [C#]              Web/IdentityServer
Duende IdentityServer Empty                                isempty             [C#]              Web/IdentityServer
Duende IdentityServer with Entity Framework Stores         isef                [C#]              Web/IdentityServer
Duende IdentityServer with In-Memory Stores and Te...      isinmem             [C#]              Web/IdentityServer
Duende IdentityServer Quickstart UI (UI assets only)       isui                [C#]              Web/IdentityServer

Identity Server は大きくわけて2つの実装があります。1つは ASP.NET Core Identity (ASP.NET Coreに含まれる認証、認可フレームワークの実装)を利用したものと、もう1つは Identity Server 自身の機能を利用した実装です。両者の違いを簡単に説明すると、例えばユーザのCRUD、サインイン、ログアウトなどの実装を、ASP.NET Core Identity のライブラリを利用して行うのか、Identity Server 側のライブラリを利用して行うかの違いになります。どちらを利用しても機能的に大きな差はありません。

認証情報のデータストアとしては永続化が必要ですから、何らかデータベースを利用することになります。どちらの実装も Entity Framework を利用できますので、最終的なデータストアはSQL Databaseが良いでしょう。テスト向けにインメモリストアの実装を試すこともできます。

GUI についてはクイックスタート的な初期テンプレートが実装されています。実際に利用する場合は、これをそのまま利用することはないため、これらを参考に独自実装することになりますが、各々のビューとコントローラーの処理については参考になるでしょう。

プロジェクトの作成

ここでは、ASP.NET Core Identity 版を利用していきます。以下のコマンドでプロジェクトのひな形を作成します。最後に、テスト用の初期ユーザーを作成するか聞かれますが Y を選択して進みましょう。デフォルトではデータベースが SQLite が使われるように構成されていますが変更方法は後述します。

$ dotnet new isaspid -o isaspid
The template "Duende IdentityServer with ASP.NET Core Identity" was created successfully.

Processing post-creation actions...
Template is configured to run the following action:
Description:
Manual instructions: Seeds the initial user database
Actual command: dotnet run /seed
Do you want to run this action (Y|N)?
y
Running command 'dotnet run /seed'...
Command succeeded.

生成したプロジェクトは、そのままデバッグ実行できます。デフォルトでは、Identity Server 自身が提供する機能として、各種情報の表示ができます。

初期ユーザとして、alice/Pass123$ が登録されているので、このIDでログインし実際の挙動を確認できるでしょう。

ただし、実際の運用などではログイン画面など必要最小限の画面以外は提供しないようにしましょう。

Webアプリケーションとの連携

ASP.NET Core Webアプリケーションを Identity Server で保護するための手順を紹介します。始めにMVCアプリケーション(.NET 5)を作成したの後、以下の依存関係を追加します。ライブラリのバージョンは適宜確認しましょう。とりあえず実行してみてURLを確認しておいください。

dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect --version 5.0.5

次に Identity Server にこのWebアプリケーションの認証に必要な情報を設定します。Config.cs を開くと Clients 配列を定義している部分があるので以下のコードを設定します。

                new Client
                {
                    ClientId = "Mvc application",
                    ClientSecrets = { new Secret("SomeSecret".Sha256()) },

                    AllowedGrantTypes = GrantTypes.Code,

                    RedirectUris = { "https://localhost:44300/signin-oidc" },
                    FrontChannelLogoutUri = "https://localhost:44300/signout-oidc",
                    PostLogoutRedirectUris = { "https://localhost:44300/signout-callback-oidc" },

                    AllowOfflineAccess = true,
                    AllowedScopes = { "openid", "profile" }
                },

修正のポイントは、以下の通りです。

  • 各種URLは、MVC アプリケーションの URL に変更する
  • シークレットの値は、GUIDなど推測されない長い値を設定する

このサンプルでは、これらの情報をコードで定義していますが、ファイルやデータベースに定義することできます。

次にMVCアプリケーション側に認証を組み込んでいきます。

Startup.csIConfigureServices メソッドに以下を追加します。設定する値は、Identity Server の設定値と合わせます。

        public void ConfigureServices(IServiceCollection services)
        {
            JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();
            services.AddAuthentication(options =>
                {
                    options.DefaultScheme = "Cookies";
                    options.DefaultChallengeScheme = "oidc";
                })
                .AddCookie("Cookies")
                .AddOpenIdConnect("oidc", options =>
                {
                    options.Authority = "https://localhost:5001";
                    options.ClientId = "Mvc application";
                    options.ClientSecret = "SomeSecret";
                    options.ResponseType = "code";
                    options.SaveTokens = true;
                });

            services.AddControllersWithViews();
        }

同じくStartup.csConfigure メソッドに以下を追加します。

    app.UseStaticFiles();

    app.UseRouting();
    app.UseAuthentication();  // ★
    app.UseAuthorization();   // ★

最後に保護するページを Authorize 属性で指定します。MVCアプリケーションのひな形には、プライバシーページがあるので、これを保護してみましょう。HomeController.cs を開き以下を追加します。

        [Authorize]

        public IActionResult Privacy()
        {
            return View();
        }

これでプライバシーページを開こうとするとログインページにリダイレクトされます。ログインするとプライバシーページが表示されるでしょう。

簡単なフローを下図で説明すると、

  1. ブラウザから Web アプリにアクセスし、許可された人しかアクセスできない保護された画面を表示しようとすると、認証されていないため、
  2. Web アプリが Identity Server のサインイン画面にリダイレクトします。
  3. ログイン画面が表示されます。
  4. ID とパスワードを入力してログインを要求します。
  5. ログイン要求が通ると、リダイレクトによって認可コードを Web アプリに提示します。
  6. Web アプリでは、認可コードを元にトークン(ID トークンやアクセストークン)を要求します。このトーンを用いて、例えば保護されたAPI(UserInfo)などを呼び出します。
  7. 保護されたページが表示されます。Web アプリは Cookie を通じてサインイン状態を維持します。

保護されたリソースへのアクセス

ユーザー属性の変更などは、Identity Server 側にユーザープロファイルの編集画面を用意するか、Web アプリ側から Identity Server に API 等を通して変更要求をする必要があります。後者のように Identity Server が保護するリソース(Identity Server 自身の API も含む)へのアクセスには、前述したアクセストークンによる認証が必要です。

以下のコードでアクセストークンを取得し、保護されたリソースにアクセスできるでしょう。

            var accessToken = await HttpContext.GetTokenAsync("access_token");
            var client = _clientFactory.CreateClient();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            var result = await client.GetAsync("https://localhost:5001/api/test");

複数のWebアプリケーションとの連携

1つの Identity Server で、複数のWebアプリケーションと連携することができます。こうすることでいわゆる SSO(シングルサインオン)を実現することができます。具体的には、先ほど Identity Server の Config.csClient にもう1つのアプリケーションを登録することで実現できます。

たとえば、 Web アプリA アクセスしサインイン状態である場合に Web アプリB へアクセスしたときに、いったんはIdentity Serverへリダイレクトされますが、Identity Server にサインイン済みであるため、サインイン画面は表示されずそのままWebアプリBに認証されます。

まとめ

本記事ではIdentity Serverについての基本的なことについて説明しました。既存のIDaaSでは対応しにくい要件にも柔軟に対応できると考えています。

お問い合わせはこちらから

問い合わせる
TOP