WebSurfer's Home

Filter by APML

.NET 10 ASP.NET Core Web API で Swagger を使用(その2)

by WebSurfer 4. April 2026 12:35

.NET 10 の ASP.NET Core Web API プロジェクトにデフォルトでインストールされている Microsoft.AspNetCore.OpenApi (以降「組込み OpenAPI」と書きます) と SwaggerUI (UI だけ) を使って [Authorize] ボタンを表示し、ベアラートークン (JWT) を使っての認証に必要な操作を行うことができるよう実装してみました。

SwaggerUI

先の記事「.NET 10 ASP.NET Core Web API で Swagger を使用」では SwaggerGen + SwaggerUI を使って実装しましたが、.NET 10 で組込み OpenAPI が使える状況ではそれは本筋ではなさそうですので。

過去はどうしていたのかも知っておいた方が理解しやすいと思いますので、.NET 8 からの経緯を以下に書きます。

  1. Visual Studio のテンプレートを使って作成する .NET 8 の ASP.NET Core Web API プロジェクトでは Swashbuckle.AspNetCore がデフォルトでインストールされている。
  2. Swashbuckle の SwaggerGen が OpenAPI ドキュメントを生成し、SwaggerUI が OpenAPI ドキュメントを解釈してブラウザ上で API のテストを行うことができる UI を提供していた。(参考: Swashbuckle と ASP.NET Core を始めよう
  3. .NET 9 以降では ASP.NET Core Web API プロジェクトには組込み OpenAPI が含まれるようになった。それゆえ Swashbuckle は含まれなくなった。(参考: Announcement: Swashbuckle.AspNetCore is being removed in .NET 9
  4. SwaggerUI は、組込み OpenAPI が生成する OpenAPI ドキュメントを解釈して UI を提供できる。したがって、組込み OpenAPI + SwaggerUI (UI だけ) で .NET 8 の時と同様にブラウザ上で API のテストができる。(参考: ローカルのアドホック テストに Swagger UI を使用する
  5. ただし、 [Authorize] ボタンを表示し、ベアラートークンを使っての認証に必要な操作を行うことができるようするためには OpenAPI ドキュメントのカスタマイズが必要 (Security Scheme と Security Requirement の追加が必要)。
  6. OpenAPI ドキュメントをカスタマイズするには、組込み OpenAPI + SwaggerUI の場合、トランスフォーマーを用いる。(参考: OpenAPI ドキュメントのトランスフォーマー
  7. Program.cs でトランスフォーマーを実装し、OpenAPI ドキュメントに Security Scheme と Security Requirement を追加すれば、前者により [Authorize] ボタンの表示とトークンの設定、後者によりベアラートークンの送信ができるようになる。

ということで、下の画像の通り、組込み OpenAPI (Microsoft.AspNetCore.OpenApi 10.0.5) と Swashbuckle.AspNetCore.SwaggerUI 10.1.7 をインストールし、[Authorize] ボタンを表示して認証に必要な操作を行うことができるよう実装してみました。

NuGet パッケージ

トランスフォーマーを実装した Program.cs のコードは以下の通りです。「方法1」のコードは Securing OpenAPI and Swagger UI with OAuth in .NET 10 を参考に、「方法2」のコードはドキュメント トランスフォーマーを使用するを参考にしました。下のコード例では、「方法2」の登録をコメントアウトしてありますので、「方法1」のみが有効になっています。どちらの方法でも OpenAPI ドキュメントのカスタマイズ結果は同じになります。

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi;
using System.Text;

namespace WebApi3
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            builder.Services.AddControllers();

            // JWT 認証の設定
            builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = builder.Configuration["Jwt:Issuer"],
                        ValidAudience = builder.Configuration["Jwt:Issuer"],
                        IssuerSigningKey = new SymmetricSecurityKey(
                            Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
                    };
                });

            builder.Services.AddAuthorization();

            // OpenAPI ドキュメントのトランスフォーマー設定(方法1)
            builder.Services.AddOpenApi(options =>
            {
                options.AddDocumentTransformer((document, context, cancellationToken) =>
                {
                    // OpenAPI ドキュメントの基本情報を設定(無くても可)
                    document.Info = new OpenApiInfo
                    {
                        Title = "ASP.NET Core Web API",
                        Version = "v1",
                        Description = "ASP.NET Core Web API with JWT authentication. " +
                            "Target Framework is .NET 10. " +
                            "Built‑in OpenAPI + SwaggerUI are used."
                    };

                    // Security Scheme を追加(JWT Bearer)
                    document.Components ??= new OpenApiComponents();
                    document.Components.SecuritySchemes ??=
                        new Dictionary<string, IOpenApiSecurityScheme>();
                    document.Components.SecuritySchemes.Add("Bearer",
                        new OpenApiSecurityScheme
                        {
                            Type = SecuritySchemeType.Http,
                            Scheme = "bearer",
                            BearerFormat = "JWT",
                            Description = "Please enter token"
                        });

                    // Security Requirement を追加
                    document.Security ??= new List<OpenApiSecurityRequirement>();
                    document.Security.Add(
                        new OpenApiSecurityRequirement
                        {
                            // インデクサ初期化子
                            [new OpenApiSecuritySchemeReference("Bearer", document)] = []
                        }
                    );

                    return Task.CompletedTask;
                });
            });

            // OpenAPI ドキュメントのトランスフォーマー設定(方法2)
            //builder.Services.AddOpenApi(options =>
            //{
            //    options.AddDocumentTransformer<JwtSecurityTransformer>();
            //});

            var app = builder.Build();

            if (app.Environment.IsDevelopment())
            {
                app.MapOpenApi();
                app.UseSwaggerUI(options =>
                {
                    options.SwaggerEndpoint("/openapi/v1.json", "v1");
                });
            }

            app.UseHttpsRedirection();

            // 認証と認可のミドルウェアを追加
            app.UseAuthentication();
            app.UseAuthorization();

            app.MapControllers();

            app.Run();

        }
    }

    // 方法2に用いる Transformer の実装
    // IAuthenticationSchemeProvider をコンストラクタへの DI で
    // 受け取ることで、登録されている認証スキームに Bearer が含
    // まれることを確認してから Security Scheme を追加する
    internal sealed class JwtSecurityTransformer(IAuthenticationSchemeProvider provider)
        : IOpenApiDocumentTransformer
    {
        public async Task TransformAsync(OpenApiDocument document,
                                         OpenApiDocumentTransformerContext context,
                                         CancellationToken cancellationToken)
        {
            // OpenAPI ドキュメントの基本情報を設定(無くても可)
            document.Info = new OpenApiInfo
            {
                Title = "ASP.NET Core Web API",
                Version = "v1",
                Description = "ASP.NET Core Web API with JWT authentication. " +
                            "Target Framework is .NET 10. " +
                            "Built‑in OpenAPI + SwaggerUI are used."
            };

            // Security Scheme を設定(JWT Bearer)
            var authenticationSchemes = await provider.GetAllSchemesAsync();
            if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
            {
                var securitySchemes = new Dictionary<string, IOpenApiSecurityScheme>
                {
                    // インデクサ初期化子
                    ["Bearer"] = new OpenApiSecurityScheme
                    {
                        Type = SecuritySchemeType.Http,
                        Scheme = "bearer",
                        BearerFormat = "JWT",
                        Description = "Please enter token"
                    }
                };
                document.Components ??= new OpenApiComponents();
                document.Components.SecuritySchemes = securitySchemes;
            }

            // Security Requirement を設定
            document.Security = [
                new OpenApiSecurityRequirement
                {
                    [new OpenApiSecuritySchemeReference("Bearer", document)] = []
                }
            ];
        }
    }
}

上のトランスフォーマーにより OpenAPI ドキュメントに Security Scheme と Security Requirement が追加されます。下の画像を見てください。赤枠が OpenAPI ドキュメント上の Security Scheme 部分、青枠が Security Requirement 部分になります。

OpenAPI ドキュメント

SwaggerUI は、上の赤枠部分を解釈して [Authorize] ボタンの表示とトークンの設定、青枠部分を解釈してベアラートークンの送信ができる実装を追加します。

Tags: , , , , ,

DevelopmentTools

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。ブログ2はそれ以外の日々の出来事などのトピックスになっています。

Calendar

<<  May 2026  >>
MoTuWeThFrSaSu
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar