この記事のまとめ
- ASP.NET Core の Web アプリケーションをローカル開発環境で実行するとき、常時認証済み状態に設定できます。
AuthenticationHandler<AuthenticationSchemeOptions>
クラスを継承して、ダミーの認証処理を行うクラスを追加します。- Program.cs で、作成したクラスを開発環境でのみ動作するように実装します。
ユースケース
Web アプリケーションに認証処理を組み込むことはよく行われていると思います。 ローカル開発環境で、本番環境に相当する認証を行おうとすると、いろいろな困難が付きまといます。
外部の IdP を利用して認証処理を行う場合、本番環境の IdP にローカル開発環境から接続することは、セキュリティ上許可されないことが普通だと思います。 このような場合、動作確認に利用する IdP を別途立てて、本番環境と切り離して開発を進めていくことになります。
ただ、このような環境を準備するのにはそれなりの時間を要します。 とにかくすぐにアプリケーションの開発に取り掛かりたい場合、認証処理の部分をダミーで通過させたくなります。 またアプリケーションのロジックとして、認可の部分はしっかり作りこみ、動作確認ができるように構成したくなります。 このようなわがままを ASP.NET Core の Web アプリケーションで実現してみます。
前提となる環境
- .NET 8
- ASP.NET Core Web API ([Open APIサポートを有効にする] をオンにしてプロジェクトを生成します)
ASP.NET Core Web API を使用しているのは、サーバーサイドの実装が一番簡単にできるからで、深い意図はありません。 ASP.NET Core MVC などでも同様の実装が可能なはずです。
実現したいこと
認証が必要で、 Admin ロールを持ったユーザーだけがアクセスできる Web API を作成します。 この Web API を呼び出したとき、ローカル開発環境なら、 Admin ロールを付与したダミーの認証済みユーザーとしてアクセスできるようにします。
認証・認可の必要なアクションメソッドを作成する
認証・認可の必要なアクションメソッドは、一般的な方法で実装していきます。
今回は Admin ロールを持った認証済みユーザーだけがアクセスできるような Web API を作成したいので、 AuthorizeAttribute
を追加して設定します。
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DummyAuthentication.Web.Controllers; [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { // 省略 [HttpGet(Name = "GetWeatherForecast")] [Authorize(Roles = "Admin")] // Admin ロールを持つ認証済みユーザーにだけアクセスを許可します。 public IEnumerable<WeatherForecast> Get() { // 省略 } }
この例では、 ASP.NET Core Web API のテンプレートに含まれている WeatherForecastController クラスの Get メソッドに対して AuthorizeAttribute
を追加しています。
Roles
引数に Admin
を設定することで、 Admin ロールを持った認証済みユーザーでなければアクセスできないアクションメソッドが完成します。
ダミーの認証ハンドラーを作成する
続いて Admin ロールを持った常時認証状態のダミーユーザーを作れる認証ハンドラーを作成します。
using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Options; using System.Security.Claims; using System.Text.Encodings.Web; namespace DummyAuthentication.Web; internal class DummyAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions> { public DummyAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder) { } protected override Task<AuthenticateResult> HandleAuthenticateAsync() { // ダミーのユーザー名とロール名を設定します。 Claim[] claims = [ new Claim(ClaimTypes.Name, "dummy_user"), new Claim(ClaimTypes.Role, "Admin") ]; var identity = new ClaimsIdentity(claims, this.Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, this.Scheme.Name); // 認証は常に成功させます。 return Task.FromResult(AuthenticateResult.Success(ticket)); } }
AuthenticationHandler<AuthenticationSchemeOptions>
を継承して、 HandleAuthenticateAsync
メソッドにダミーの認証済みユーザー作成処理を実装します。
Admin ロールを忘れずに付与しておきましょう。
ダミーの認証ハンドラーを利用するように構成する
作成したダミーの認証ハンドラーは、 Program.cs で有効にしないと使えません。 ダミーの認証ハンドラーは開発環境でのみ使いたいので、環境変数を見て場合分けしています。
using DummyAuthentication.Web; using Microsoft.AspNetCore.Authentication; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); if (builder.Environment.IsDevelopment()) { // ローカル開発環境でのダミーの認証ハンドラーを登録します。 builder.Services.AddAuthentication("DummyAuthentication") .AddScheme<AuthenticationSchemeOptions, DummyAuthenticationHandler>("DummyAuthentication", null); builder.Services.AddAuthorization(); } else if (builder.Environment.IsProduction()) { // 本番環境での認証ハンドラーはここで登録します。 } // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); // 認証ミドルウェアを追加します。 app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
動作確認
本当に認証済みとして扱われているのか確かめるため、 WeatherForecastController.Get
メソッドでユーザーオブジェクトの情報をいくつかログに出力しておきます。
この状態で、 Web アプリケーションを実行してみます。
[HttpGet(Name = "GetWeatherForecast")] [Authorize(Roles = "Admin")] // Admin ロールを持つ認証済みユーザーにだけアクセスを許可します。 public IEnumerable<WeatherForecast> Get() { // 動作確認のため、ユーザーの情報をログに出力します。 this.logger.LogInformation("Authenticated user:{UserName}", this.User.Identity?.Name); this.logger.LogInformation("User is authenticated:{IsAuthenticated}", this.User.Identity?.IsAuthenticated); this.logger.LogInformation("Has \"Admin\" role:{HasAdminRole}", this.User.IsInRole("Admin")); // 省略 }
[Open API サポートを有効にする]をオンにして生成した ASP.NET Core Web API のアプリケーションを実行すると、 Swagger の画面が起動します。
この画面から、 WeatherForecastController.Get
の Web API を実行してみましょう。
まず [GET /WeatherForecast] のアコーディオンを開き、 [Try it out] ボタンを押下します。
続いて、 [Execute] ボタンを押下します。
すると Web API が動作し、レスポンスを返却していることが確認できます。 このとき、クライアント側では認証に関連する操作を一切行っていません。 しかし、認証が必要で Admin ロールがないと呼び出せないはずの Web API が動作しています。
アクションメソッドに仕込んだログも確認してみましょう。
ユーザー名はダミーの認証ハンドラーで設定したユーザー名が反映されています。
認証状態も「認証済み」となっており、ダミーの認証ハンドラーでダミーの認証状態を作り出すことに成功しています。
また User.IsInRole
メソッドを使うと、 Admin ロールを持っていることも確認できます。
サンプルコード
本稿で紹介したサンプルコードは、以下からダウンロードできます。