Computer Programming
Friday, July 7, 2023
IdentityServerと.NET同時に使う時に必要なClaimが見つからないの対策
ドキュメントを参考するだけで本当に正しいプログラム作れない。
バスタに乗って河口湖に向かう

私はRBACとOIDC両方使っています。そしてDuende IdentityServerをOIDC Providerとして、.NETのMVCプロジェクトはそれを通して認証します。

RBACといえば、Roleの値が必要でしょうね。でもRoleというキーはOIDCのScopeの世界にないです。だから自分でカスタマイズのScopeとして実装しないといけないです。

まず一番やることは、自分のUserClaimsPrincipalFactoryを作ることです。

public class ApplicationUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
  protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
  {
    var identity = await base.GenerateClaimsAsync(user);
    
    var roles = await _userManager.GetRolesAsync(user);
   identity.AddClaims(roles.Select(role => new Claim(JwtClaimTypes.Role, role)));
    // 他のClaimもいるなら、ここに追加して
    // ...
    return identity;
  }
}
ApplicationUserClaimsPrincipalFactory.cs

このあとは、作ったClaimsPrincipalFactoryを利用するように登録します。

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
.AddClaimsPrincipalFactory<ApplicationUserClaimsPrincipalFactory>()
Program.cs

これで、IdentityServer側、ソースに関する変更は全て完了です。このあと、Identity Resourcesに role というリソースを追加して、さらに role という UserRoleをAPI ResourceとClientのAllowed Scopeに追加してください。これはTokenにRoleのキーを入れる指示とRoleのClaimを受け取る許可の意味が含まれています。追加する方法は、ソースに起動するとき初期化するロジックを書くか、管理者ツールで設定するかどっちでもいいです。私は管理者システムを作ったから、Webでこれらの資源を更新します。

ここまできたら、もうIdentityServerからRoleのClaim送ってくれます。しかし、.NETはちゃんと理解してCookieに書いてくれるか。答えはネガティヴ。

openIdConnectOptions.Scope.Add("role");
openIdConnectOptions.ClaimActions.MapJsonKey("role", "role", "role");
openIdConnectOptions.TokenValidationParameters.RoleClaimType = "role";
Program.cs

以上の3行はAddOpenIdConnect()の時に追加してください。1行目は、roleのClaimが欲しい意味で、IdentityServer側のAllowed Scopeと関連しています。2行目は、認証が必要なサーバーが受け取った Role ClaimをCookieに入れる指示です。3行目は、受け取ったRoleキーをそのまま受け取って、名前書き換えないでと.NETに命令する意味です。

これでRBACは使えるようになるはずです。