トークンベース (JWT) の認証を実装した ASP.NET Core Web API に Role による承認を追加する話を書きます。(認証と承認は違いますのでご注意ください)
クッキーベースの ASP.NET Identity 認証システムを実装した ASP.NET Web アプリでは、認証に加えて承認によるアクセスコントロールが可能です。承認には Role が使われます。例えばサイト管理者がマネージャー・ゲスト・管理者・メンバーなどといった Role を定義し、ユーザー別に Role をアサインすることにより細かいアクセスコントロールが可能になっています。
例えばアクションメソッドに [Authorize(Roles = "Admin")] という属性を付与したとすると、ユーザーが有効な ID とパスワードでログインして認証は通っていたとしても、Admin という Role を持っていないと承認されず、ユーザーはそのアクションメソッドにはアクセスできなくなります。
それは JWT ベースの認証機能を実装した Web API でも同様です。先の記事「Blazor WASM から ASP.NET Core Web API を呼び出し」で紹介した WeatherForecastController コントローラの Get() メソッドで、以下のように [Authorize] 属性を [Authorize(Roles = "Admin")] に変更してから Blazor アプリからアクセスすると、
// [Authorize]
[Authorize(Roles = "Admin")]
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
以下の画像のように HTTP 403 Forbidden 応答 (サーバーは要求を理解しましたが、要求の実行を拒否しています・・・と言う意味) が帰ってきてデータの取得に失敗します。ちなみに、認証が通らない場合は HTTP 401 Unauthorized 応答が返ってきます。
上の画像の #11 では、Blazor アプリからは有効な ID とパスワードが送信されるので認証は通ってトークンが返ってきています。そして、#13 でそのトークンを要求ヘッダに含めて上のアクションメソッド Get に要求をかけています。その結果、サーバー側では認証には成功するものの Admin ロールを持っていないので承認が通らず HTTP 403 応答が返ってきています。
Role による承認が通るようにするには、上の画像の #11 で返されるトークンに Admin ロールを持っているという情報を含める必要があります。それにはトークンを生成する際、Claims 情報として Admin ロールを追加してやります。
具体的には、先の記事「Blazor WASM から ASP.NET Core Web API を呼び出し」で紹介したトークンを発行する API の BuildToken メソッドで、以下のように Admin ロール情報を Claims に追加します。
private string BuildToken()
{
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_config["Jwt:Key"]!));
var creds = new SigningCredentials(
key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Issuer"],
// Admin ロール情報を Claims に追加
claims: [ new Claim(ClaimTypes.Role, "Admin") ],
notBefore: null,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
これにより発行されるトークンには Admin ロールを持っているという情報が含まれます。以下の画像は発行されたトークンを JWT というサイトでデコードしたものです。赤枠部分を見てください。
そのトークンを要求ヘッダに含めて要求をかければ承認が通って、下の画像の #6 の通りデータが返され、
Blazor アプリには期待通り結果が表示されます。