ASP.NET CoreにおけるJWT認証:実装から動作確認まで完全ガイド
ASP.NET Core で安全な API を構築するには、適切な認証が不可欠です。このガイドでは、JWT(JSON Web Token)認証をゼロから実装する手順を詳しく解説します。

前提条件
始める前に、以下を準備してください:
- .NET 8 SDK 以降がインストールされていること
- コードエディタ(Visual Studio、VS Code、または Rider)
- C# と REST API の基本的な理解
Step 1: ASP.NET Core Web API プロジェクトの作成
# 新しい Web API プロジェクトを作成 dotnet new webapi -n JwtAuthDemo cd JwtAuthDemo # 必要な NuGet パッケージをインストール dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer dotnet add package System.IdentityModel.Tokens.Jwt
💡 NuGet パッケージとは? NuGet は .NET のパッケージマネージャーで、Node.js の npm に相当します。パッケージは、プロジェクトに機能を追加するための事前にビルドされたライブラリです。
Step 2: appsettings.json に JWT 設定を追加
appsettings.json に JWT の設定を追加します:
{ "Jwt": { "Key": "YourSuperSecretKeyThatIsAtLeast32CharactersLong!", "Issuer": "https://yourdomain.com", "Audience": "https://yourdomain.com", "ExpiryMinutes": 60 }, "Logging": { "LogLevel": { "Default": "Information" } } }
用語解説
- Key(秘密鍵): JWT に署名するために使用される秘密の鍵。安全に保管し、絶対に公開してはいけません。
- Issuer(発行者): トークンを発行したエンティティ(通常は API サーバー)。
- Audience(対象者): トークンの意図された受信者(通常は API またはクライアントアプリ)。
- ExpiryMinutes(有効期限): トークンが有効である時間(分単位)。
Step 3: モデルの作成
Models フォルダを作成し、以下のファイルを追加します:
LoginRequest.cs
namespace JwtAuthDemo.Models; public class LoginRequest { public string Username { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; }
LoginResponse.cs
namespace JwtAuthDemo.Models; public class LoginResponse { public string Token { get; set; } = string.Empty; public DateTime Expiration { get; set; } }
Step 4: JWT サービスの作成
Services フォルダを作成し、JwtService.cs を追加します:
using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using Microsoft.IdentityModel.Tokens; namespace JwtAuthDemo.Services; public class JwtService { private readonly IConfiguration _configuration; public JwtService(IConfiguration configuration) { _configuration = configuration; } public string GenerateToken(string username, string role) { // 1. Claims(ユーザー情報)を作成 var claims = new[] { new Claim(ClaimTypes.Name, username), new Claim(ClaimTypes.Role, role), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; // 2. 設定ファイルから秘密鍵を取得 var key = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]!) ); // 3. 署名資格情報を作成 var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); // 4. 有効期限を設定 var expiry = DateTime.UtcNow.AddMinutes( Convert.ToDouble(_configuration["Jwt:ExpiryMinutes"]) ); // 5. トークンを作成 var token = new JwtSecurityToken( issuer: _configuration["Jwt:Issuer"], audience: _configuration["Jwt:Audience"], claims: claims, expires: expiry, signingCredentials: credentials ); // 6. シリアライズされたトークン文字列を返す return new JwtSecurityTokenHandler().WriteToken(token); } }
コードの詳細解説
- Claims(クレーム): トークンに埋め込まれるユーザー情報を含むキーと値のペア。
- SymmetricSecurityKey(対称セキュリティキー): トークンの署名と検証の両方に使用される暗号化キー。
- SigningCredentials(署名資格情報): トークンの署名に使用されるアルゴリズム(HMAC-SHA256)を指定します。
- JwtSecurityToken: すべての情報を含む実際のトークンオブジェクト。
Step 5: Program.cs で認証を設定
Program.cs の内容を以下に置き換えます:
using System.Text; using JwtAuthDemo.Services; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; var builder = WebApplication.CreateBuilder(args); // サービスをコンテナに追加 builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // JwtService を登録 builder.Services.AddSingleton<JwtService>(); // 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:Audience"], IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!) ) }; }); builder.Services.AddAuthorization(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); // 重要:順序が大事! app.UseAuthentication(); // UseAuthorization の前に呼び出す必要がある app.UseAuthorization(); app.MapControllers(); app.Run();
⚠️ 重要:ミドルウェアの順序
UseAuthentication()はUseAuthorization()の前に呼び出す必要があります。認証は「あなたが誰か」を識別し、認可は「あなたが何をできるか」を決定します。
Step 6: Auth コントローラーの作成
Controllers/AuthController.cs を作成します:
using JwtAuthDemo.Models; using JwtAuthDemo.Services; using Microsoft.AspNetCore.Mvc; namespace JwtAuthDemo.Controllers; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly JwtService _jwtService; public AuthController(JwtService jwtService) { _jwtService = jwtService; } [HttpPost("login")] public IActionResult Login([FromBody] LoginRequest request) { // 本番環境では、データベースに対して検証する if (request.Username == "admin" && request.Password == "password123") { var token = _jwtService.GenerateToken(request.Username, "Admin"); var expiration = DateTime.UtcNow.AddMinutes(60); return Ok(new LoginResponse { Token = token, Expiration = expiration }); } return Unauthorized(new { message = "認証情報が無効です" }); } }
Step 7: 保護されたエンドポイントの作成
Controllers/WeatherController.cs を作成します:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace JwtAuthDemo.Controllers; [ApiController] [Route("api/[controller]")] public class WeatherController : ControllerBase { [HttpGet("public")] public IActionResult GetPublicData() { return Ok(new { message = "これは公開データです" }); } [Authorize] // このエンドポイントは認証が必要 [HttpGet("protected")] public IActionResult GetProtectedData() { var username = User.Identity?.Name; return Ok(new { message = "これは保護されたデータです", user = username }); } [Authorize(Roles = "Admin")] // Admin ロールが必要 [HttpGet("admin")] public IActionResult GetAdminData() { return Ok(new { message = "管理者専用データ" }); } }
Step 8: API のテスト
アプリケーションを実行します:
dotnet run
テスト 1: ログインしてトークンを取得
curl -X POST https://localhost:7000/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"password123"}'
レスポンス:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiration": "2026-01-23T11:00:00Z" }
テスト 2: 保護されたエンドポイントにアクセス
curl -X GET https://localhost:7000/api/weather/protected \ -H "Authorization: Bearer YOUR_TOKEN_HERE"
成功時のレスポンス:
{ "message": "これは保護されたデータです", "user": "admin" }
よくある問題と解決策
問題 1: 401 Unauthorized
原因: トークンが欠落しているか無効です。
解決策: Authorization ヘッダーに Bearer プレフィックス付きでトークンを送信していることを確認してください。
問題 2: Token Validation Failed
原因: appsettings.json の秘密鍵が、トークンの署名に使用されたものと一致していません。
解決策: 鍵を変更した後、アプリケーションを再起動してください。
セキュリティのベストプラクティス
- 秘密情報をハードコードしない: 本番環境では環境変数または Azure Key Vault を使用します。
- HTTPS を使用: 常に暗号化された接続でトークンを送信します。
- 短い有効期限: トークンの有効期限を 15〜60 分に設定します。
- リフレッシュトークンを実装: ユーザーが資格情報を再入力せずに新しいトークンを取得できるようにします。
- すべてのリクエストで検証:
[Authorize]属性により、トークンが確認されます。
まとめ
これで、ASP.NET Core で完全に機能する JWT 認証システムができました。このセットアップは、安全な API を構築するための強固な基盤を提供します。