mcpField
A
authentication

authentication

github.com/codewithmukeshセキュリティ7913.0k 回インストール12 週間前に更新
リポジトリ

authentication について

ASP.NET アプリケーション開発者向けの .NET 認証・認可スキルです。Identity、JWT や Cookie による認証、ポリシーベースのアクセス制御を扱います。

主な機能

  1. 01ASP.NET Identity によるユーザー管理
  2. 02JWT と Cookie 認証
  3. 03ポリシーベースの認可
  4. 04OpenID Connect の設定
  5. 05シークレットの安全な管理

活用シーン

  1. 01REST API エンドポイントの保護
  2. 02Web アプリへのログイン追加
  3. 03外部 ID プロバイダーとの連携

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/codewithmukesh/dotnet-claude-kit --skill authentication

インストール後、Claude Code で/authenticationを入力して読み込まれたか確認します。

詳細

認証と認可

基本原則

  1. ユーザー管理には ASP.NET Identity を使用してください — 独自のユーザーストアを構築しないでください。Identity は、パスワードのハッシュ化、ロックアウト、二要素認証、メール確認に加え、(.NET 10 以降では)パスワードレスログインに対応する組み込みのパスキー/WebAuthn サポートを処理します。
  2. API には JWT、Web アプリには Cookie を使用してください — API では Bearer トークン認証を使用し、Blazor/MVC アプリでは Cookie 認証を使用します。
  3. ロールよりポリシーベースの認可を優先してください — ポリシーはテスト可能で、組み合わせ可能であり、[Authorize(Roles = "Admin")] よりも柔軟に記述できます。
  4. シークレットをコードに保存しないでください — 開発環境ではユーザーシークレットを使用し、本番環境では Azure Key Vault/環境変数を使用します。

パターン

JWT Bearer 認証
// Program.cs
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"]!)),
            ClockSkew = TimeSpan.Zero
        };
    });

builder.Services.AddAuthorization();
トークンの生成

Microsoft.IdentityModel.JsonWebTokens の JsonWebTokenHandler を使用してください。これは保守されている span ベースのハンドラーであり、ASP.NET Core 自体もこれを使って検証します。JwtSecurityTokenHandler(System.IdentityModel.Tokens.Jwt)はレガシーのスタックです。

public sealed class TokenService(IConfiguration config, TimeProvider clock)
{
    private static readonly JsonWebTokenHandler TokenHandler = new();

    public string GenerateToken(User user, IEnumerable<string> roles)
    {
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"]!));
        var now = clock.GetUtcNow();

        var descriptor = new SecurityTokenDescriptor
        {
            Issuer = config["Jwt:Issuer"],
            Audience = config["Jwt:Audience"],
            IssuedAt = now.UtcDateTime,
            Expires = now.AddHours(1).UtcDateTime,
            Claims = new Dictionary<string, object>
            {
                [JwtRegisteredClaimNames.Sub] = user.Id,
                [JwtRegisteredClaimNames.Email] = user.Email!,
                [JwtRegisteredClaimNames.Name] = user.UserName!,
                ["roles"] = roles.ToArray()
            },
            SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
        };

        return TokenHandler.CreateToken(descriptor);
    }
}
ポリシーベースの認可
// Define policies
builder.Services.AddAuthorizationBuilder()
    .AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"))
    .AddPolicy("CanManageOrders", policy => policy
        .RequireAuthenticatedUser()
        .RequireClaim("permission", "orders:write"))
    .AddPolicy("MinimumAge", policy => policy
        .AddRequirements(new MinimumAgeRequirement(18)));

// Custom requirement + handler
public class MinimumAgeRequirement(int minimumAge) : IAuthorizationRequirement
{
    public int MinimumAge => minimumAge;
}

public class MinimumAgeHandler(TimeProvider clock) : AuthorizationHandler<MinimumAgeRequirement>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        MinimumAgeRequirement requirement)
    {
        var dateOfBirthClaim = context.User.FindFirst("date_of_birth");
        if (dateOfBirthClaim is not null &&
            DateOnly.TryParse(dateOfBirthClaim.Value, out var dob) &&
            dob.AddYears(requirement.MinimumAge) <= DateOnly.FromDateTime(clock.GetUtcNow().DateTime))
        {
            context.Succeed(requirement);
        }
        return Task.CompletedTask;
    }
}
エンドポイントの保護
// Protect an entire group
app.MapGroup("/api/admin")
    .WithTags("Admin")
    .RequireAuthorization("AdminOnly")
    .MapAdminEndpoints();

// Protect individual endpoints
group.MapPost("/", CreateOrder)
    .RequireAuthorization("CanManageOrders");

// Allow anonymous on a protected group
group.MapGet("/public-info", GetPublicInfo)
    .AllowAnonymous();
OpenID Connect(外部 ID プロバイダー)
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    options.Authority = builder.Configuration["Oidc:Authority"];
    options.ClientId = builder.Configuration["Oidc:ClientId"];
    options.ClientSecret = builder.Configuration["Oidc:ClientSecret"];
    options.ResponseType = "code";
    options.SaveTokens = true;
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("email");
});
現在のユーザーへのアクセス
// In minimal API handlers — inject ClaimsPrincipal or HttpContext
group.MapGet("/me", (ClaimsPrincipal user) =>
{
    var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
    var email = user.FindFirstValue(ClaimTypes.Email);
    return TypedResults.Ok(new { userId, email });
}).RequireAuthorization();

アンチパターン

あらゆる場所でロール文字列を使用しない
// BAD — magic strings, hard to refactor, not testable
[Authorize(Roles = "Admin,SuperAdmin,Manager")]
public class AdminController { }

// GOOD — policy-based
builder.Services.AddAuthorizationBuilder()
    .AddPolicy("AdminAccess", p => p.RequireRole("Admin", "SuperAdmin", "Manager"));

group.MapGet("/", Handler).RequireAuthorization("AdminAccess");
シークレットを appsettings.json に保存しない
// BAD — committed to source control
{
  "Jwt": {
    "Key": "super-secret-key-12345"
  }
}
# GOOD — use user secrets in development
dotnet user-secrets set "Jwt:Key" "super-secret-key-12345"
トークンの検証を省略しない
// BAD — disabling validation
options.TokenValidationParameters = new TokenValidationParameters
{
    ValidateIssuer = false,      // DON'T
    ValidateAudience = false,    // DON'T
    ValidateLifetime = false,    // DEFINITELY DON'T
};

// GOOD — validate everything (see JWT Bearer Authentication pattern above for full setup)

判断ガイド

シナリオ推奨事項
REST APIJWT Bearer 認証
Blazor Server/MVCCookie 認証
外部 ID プロバイダーOpenID Connect
ユーザー登録/ログインASP.NET Identity
パスワードレスログインASP.NET Identity のパスキー(WebAuthn、.NET 10 以降に組み込み)
権限の確認ポリシーベースの認可
マルチテナント APIテナントクレームを使用したクレームベース認証
API 間の通信クライアントクレデンシャル(OAuth 2.0)
シンプルな API キーカスタム AuthenticationHandler<T>

コメント