2018年11月10日土曜日

IdentityServer4 で ログインとロールベースの認証を行うまで

ユーザ認証やら何やらで IdentityServer4 を調べて、Roleベースの認証がとりあえずできるようになったので、手順を記載したもの。
コレが良い手法なのかはわからないが、ともかく、一番余分なコードを書かないで済みそうな方法だとは思う。

■概要

IdentityServer4の公式が提示しているサンプルを修正して、Roleベースの認証の動作確認を行うまでの手順。

■前提条件

  • 以下の環境で動作を確認: Visual Studio 2017 .NET Core 2.1 IdentiryServer4

■修正のベースにしたサンプルの準備

  • 以下を落としてくる: https://github.com/IdentityServer/IdentityServer4.Samples
  • 上記で、以下のフォルダに入っているソリューションを修正元として使う: IdentityServer4.Samples\Quickstarts\6_AspNetIdentity
  • ダブルクリックで、.sln ファイルを開いて、修正。

■IdentityServer側プロジェクトの修正内容

「IdentityServerWithAspNetIdentity」プロジェクトに、ユーザ認証にかかわる処理がまとまっているので、そこのファイルを修正する。

◆ユーザの準備

  • SeedDataで、ログインユーザの作成を行っているので、そのユーザのClaimに、何かRoleっぽい物を追加する。
    サンプル追加例)
new Claim("mvc_roles", "admin")

※なお、この例では、”bob”にだけ”admin”権限をつけた。

◆Scope 追加

  • Config で IdentityServer4 の OpenID にかかわる色々の設定が行われているので、それも修正
    GetIdentityResources メソッドで戻している IdentityResources に、ユーザに追加したRoleっぽいClaimの名前を追加します。(これをしないと、クライアントから取得できない
    サンプル追加例)
               new IdentityResource()
               {
                   Name = "role_for_mvc",
                   DisplayName = "権限",
                   UserClaims = { "mvc_roles" },
                   Required = true
               }

  • “UserClaims” に、SeedData で追加したロール向けClaim の名前を設定。
     GetClients メソッドで返している Client の内、MVC クライアントに対応する「ClientId = "mvc"」の AllowedScopes に、 上記で追加した IdentityResources の名前を追加。
    修正後のコード例)
                   AllowedScopes =
                   {
                       IdentityServerConstants.StandardScopes.OpenId,
                       IdentityServerConstants.StandardScopes.Profile,
                       "api1",
                       "role_for_mvc"
                   },

これで、IdentityServer4 側の修正は完了。

■MVCクライアント側の修正内容

クライアント側に、Roleベースの認証を試せるだけの処理を追記。

◆プロジェクト設定変更

  • SDK を ASP.NET Core 2.1 に変更。(2.1にしかないクラスを使いたいので) 1. “MvcClient”プロジェクトを右クリックし、「プロパティ」を選択 2. アプリケーションのターゲットフレームワークで「.NET Core 2.1」を選択
    3. “MvcClient”プロジェクトの「依存関係」を右クリックし、「NuGetパッケージの管理」を選択 4. Nuget パッケージの管理で、全てのパッケージを更新。

◆Startup の修正

  • Startup の ConfigureServices メソッドを修正し、追加したClaimを取得するようにする。 修正例)
                   options.Scope.Add("api1");
                   options.Scope.Add("offline_access");
                   options.Scope.Add("role_for_mvc"); // 追加した行

                   options.ClaimActions.Add(new MapAllClaimsAction()); // 追加した行

  • 追加したClaimでRoleの判定をするように変更。上記の修正を加えた行の下に、以下も追加:
                   options.TokenValidationParameters = new TokenValidationParameters
                   {
                       RoleClaimType = "mvc_roles"
                   };

◆Controller の修正

  • 実験のため、HomeController に、Roleをくっつけた Authorize 属性のあるメソッドを追加(ここではSecureメソッドをコピペして改変)
    例:追加したメソッド)
       [Authorize(Roles ="admin")]
       public IActionResult SecureWithRole()
       {
           ViewData["Message"] = "Secure page(with role).";

           return View("Secure");
       }


修正は以上。
これで、動作の確認ができるようになったはず。

■蛇足:動かし方

  • とりあえずの動作確認方法 1. 下記プロジェクトのWebサーバをすべて起動
     IdentityServerWithAspNetIdentity  MvcClient  Api 2. http://localhost:5002 にアクセス 3. ヘッダ部分のSecure リンクをクリックすると、ログイン画面が出てくるはずなので、ログイン(SeedDataが登録されていれば、bob か alice でログインできるはず) 4. ユーザ情報へのアクセス許可を求められるので、許可して進む 5. Secure画面が表示される(Authenticate属性だけの画面) 6. Role で保護された画面を、URLを変更して、表示する(この例だとhttp://localhost:5002/SecureWithRole に変更してアクセス) 7. ログインしたユーザに権限があれば、問題なくアクセスできる(はず)。ユーザをRoleが無い側のユーザに切り替えてアクセスすると、とりあえずアクセスが拒否される(はず) 
  • なお、各サーバは Visual Studio 上から動かすより、コマンドライン上から動かしてしまった方が多分、楽だと思われる: コマンドプロンプトで各プロジェクトのフォルダに移動したうえで: dotnet run あるいは: dotnet run -p (各プロジェクトのフォルダパス)

参考情報:

ほぼこのブログのまま - http://benfoster.io/blog/asp-net-identity-role-claims
API:https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.oauth.claims.mapallclaimsaction?view=aspnetcore-2.1
ドキュメント:http://docs.identityserver.io/en/release/

以上。