JWTはロールベースでもカスタムポリシーベースでも、実装手順は同じです。カスタムポリシーベースの手順は以下の通りです:
- appsettings.jsonでJWTのパラメータを設定する
- 認証と認可のサービスとミドルウェアを追加し、それをポリシーモードとポリシー名で設定する
- トークン生成メソッドとトークンパラメータの確認メソッドを定義する
- ログイン時に身元を確認しトークンを配布する
-
AuthorizationHandler<IAuthorizationRequirement>
を継承し、認証ルールを実装する
次に具体的な実装を見ていきましょう。
JWT設定
"JWTConfig": {
"Secret": "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"Issuer": "gsw",
"Audience": "everone",
"Expires": 10000
}
カスタムポリシーの実装
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
var builder = WebApplication.CreateBuilder();
// JWT設定をバインドする
var jwtConfig = new JWTConfig();
builder.Configuration.GetSection("JWTConfig").Bind(jwtConfig);
builder.Services.AddSingleton(jwtConfig);
// 認可データを注入(キャッシュに置いて認証時に使用することも可能)
builder.Services.AddSingleton(new List<Permission> {
new Permission { RoleName = "admin", Url = "/helloadmin", Method = "get" }
});
// カスタムポリシー処理タイプを注入
builder.Services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
// 認証と認可を注入し、Policy名をPermissionに設定
builder.Services
.AddAuthorization(options =>
{
var permissionRequirement = new PermissionRequirement();
options.AddPolicy("Permission", policy => policy.AddRequirements(permissionRequirement));
})
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, opt =>
{
opt.RequireHttpsMetadata = false;
opt.TokenValidationParameters = JwtToken.CreateTokenValidationParameters(jwtConfig);
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
// 「Permission」ポリシーに基づいて認証する3つのgetリクエストをマップ
app.MapGet("/hellosystem", (ILogger<Program> logger, HttpContext context) =>
{
var message = $"hello,system,{context.User?.Identity?.Name}";
logger.LogInformation(message);
return message;
}).RequireAuthorization("Permission");
app.MapGet("/helloadmin", (ILogger<Program> logger, HttpContext context) =>
{
var message = $"hello,admin,{context.User?.Identity?.Name}";
logger.LogInformation(message);
return message;
}).RequireAuthorization("Permission");
app.MapGet("/helloall", (ILogger<Program> logger, HttpContext context) =>
{
var message = $"hello,all roles,{context.User?.Identity?.Name}";
logger.LogInformation(message);
return message;
}).RequireAuthorization("Permission");
// ログインしてトークンを配布
app.MapPost("/login", [AllowAnonymous] (ILogger<Program> logger, LoginModel login, JWTConfig jwtConfig) =>
{
logger.LogInformation("login");
if (login.UserName == "gsw" && login.Password == "111111")
{
var now = DateTime.UtcNow;
var claims = new Claim[] {
new Claim(ClaimTypes.Role, "admin"),
new Claim(ClaimTypes.Name, "桂素伟"),
new Claim(ClaimTypes.Sid, login.UserName),
new Claim(ClaimTypes.Expiration, now.AddSeconds(jwtConfig.Expires).ToString())
};
var token = JwtToken.BuildJwtToken(claims, jwtConfig);
return token;
}
else
{
return "username or password is error";
}
});
app.Run();
実行結果
(Translated by GPT)