.NET 8公開後、JWT認証におけるAOTの解決

.NET 8がリリースされたことにより、AOTによるJWT認証も完了し、基本的なAOT APIを構築することが可能となりました。これにより、何らかのシンプルなAPIプロジェクトにAOTを導入できるようになりました。AOTの利点については、以下を参照してください：
https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/native-aot?view=aspnetcore-8.0。
以下は、JWT認証を追加したシンプルなデモです、時間が限られているため、参考までにしてください。
```
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security;
using System.Security.Claims;
using System.Text;
using System.Text.Json.Serialization;

var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.ConfigureHttpJsonOptions(options =>{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

#region 策略
builder.Services
    .AddAuthorization(options =>
    {
        //策略名を追加
        options.AddPolicy("Permission", policyBuilder => policyBuilder.AddRequirements(new PermissionRequirement()));
    }).AddSingleton(new List<Permission> {
    new Permission { RoleName = "admin", Url = "/Policy", Method = "get" },
    new Permission { RoleName = "admin", Url = "/todos", Method = "get" },
}).AddSingleton<IAuthorizationHandler, PermissionHandler>().AddAuthentication(options =>{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(opt =>{
    //トークン検証パラメータ
    opt.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("1234567890abcdefg1234567890abcdefg")),
        ValidateIssuer = true,
        ValidIssuer = "http://localhost:5274",
        ValidateAudience = true,
        ValidAudience = "http://localhost:5274",
        ClockSkew = TimeSpan.Zero,
        RequireExpirationTime = true,
    };
});
#endregion

var app = builder.Build();

var sampleTodos = new Todo[] {
    new(1, "Walk the dog"),
    new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)),
    new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))),
    new(4, "Clean the bathroom"),
    new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2)))
};

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos).RequireAuthorization("Permission"); ;
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound()).RequireAuthorization("Permission");

#region 策略
app.MapGet("/login", () =>{
    //JWTSecurityTokenHandlerでtokenを生成
    return new JwtSecurityTokenHandler().WriteToken(
        new JwtSecurityToken(
            issuer: "http://localhost:5274",
            audience: "http://localhost:5274",
            claims: new Claim[] {
                new Claim(ClaimTypes.Role, "admin"),
                new Claim(ClaimTypes.Name, "桂素伟")
            },
            notBefore: DateTime.UtcNow,
            expires: DateTime.UtcNow.AddSeconds(500000),
            signingCredentials: new SigningCredentials(
                new SymmetricSecurityKey(Encoding.ASCII.GetBytes("1234567890abcdefg1234567890abcdefg")),
                SecurityAlgorithms.HmacSha256Signature)
            )
        );
});
app.MapGet("/policy", (ClaimsPrincipal user) => $"こんにちはユーザーさん：{user.Identity?.Name}, ロール：{user.Claims?.Where(s => s.Type == ClaimTypes.Role).First().Value}. これはポリシーです！").RequireAuthorization("Permission");
#endregion

app.Run();

public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false);

[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext{}

#region 策略
public class PermissionRequirement : IAuthorizationRequirement{}
public class Permission{
    public string? RoleName { get; set; }
    public string? Url { get; set; }
    public string? Method { get; set; }
}

public class PermissionHandler : AuthorizationHandler<PermissionRequirement>{
    private readonly List<Permission> _userPermissions;
    public PermissionHandler(List<Permission> permissions)
    {        _userPermissions = permissions;    }
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
    {
        if (context.Resource is DefaultHttpContext)
        {
            var httpContext = context.Resource as DefaultHttpContext;
            var questPath = httpContext?.Request?.Path;
            var method = httpContext?.Request?.Method;
            var isAuthenticated = context?.User?.Identity?.IsAuthenticated;
            if (isAuthenticated.HasValue && isAuthenticated.Value)
            {
                var role = context?.User?.Claims?.SingleOrDefault(s => s.Type == ClaimTypes.Role)?.Value;
                if (_userPermissions.Where(w => w.RoleName == role && w.Method?.ToUpper() == method?.ToUpper() && w.Url?.ToLower() == questPath).Count() > 0)
                {
                    context?.Succeed(requirement);
                }
                else
                {
                    context?.Fail();
                }
            }
        }
        return Task.CompletedTask;
    }
}
#endregion
```
デモ結果は以下のとおりです：

ログイン：
![alt 画像](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRAAFBSia8p6hFpic6oTJg4BKByB8XSia9eNdxtDfcwopu4yZEcjL2TCMRDjtJYkuhKy8ddFBFxDBwBOA/640?wx_fmt=png)
ログイン情報を見る：
![alt 画像](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRAAFBSia8p6hFpic6oTJg4BKB4d5vHr2Em6fX2wS8sbFgIxY9IBUMibibTGNOv7IE8AZ1Yz63oxZn081g/640?wx_fmt=png)
データインターフェースを確認する：
![alt 画像](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRAAFBSia8p6hFpic6oTJg4BKBoqQtKyNhicnIyNBibZt8MTccCfGWdxnWVttR44eZBnuh1lusVWV5PHaA/640?wx_fmt=png)
まだ多くのテンプレートがAOTをサポートしていない、または完全にサポートしていない状況です。以下は現在の.NET 8の対応状況です。
機能　完全サポート　部分サポート　未サポート
gRPC：	✅完全サポート	
Minimal APIs：	✅部分サポート	
MVC：	❌未サポート
Blazor： ❌未サポート
SignalR	：❌未サポート
JWT認証：	✅完全サポート	
その他の認証：	❌未サポート
CORS：	✅完全サポート	
ヘルスチェック：	✅完全サポート	
HTTPログ記録：	✅完全サポート	
ローカライゼーション：	✅完全サポート	
出力キャッシュ：	✅完全サポート	
レート制限：	✅完全サポート	
リクエスト解凍：	✅完全サポート	
レスポンスキャッシュ：	✅完全サポート	
レスポンス圧縮：	✅完全サポート	
リライト：	✅完全サポート	
セッション：❌未サポート
SPA	：❌未サポート
静的ファイル	：✅完全サポート	
WebSockets：	✅完全サポート	

(Translated by GPT)