質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
.NET Core

.NET Coreは、マネージソフトウェアフレームワークでオープンソースで実装されています。クロスプラットフォームを前提に考えられており、Windows/Mac/Linuxで動くアプリケーションを作成することが可能です。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

Q&A

解決済

1回答

3355閲覧

ASP.NET COREでロールの確認(IsInRoleAsync)をするタイミング

woodcube

総合スコア32

.NET Core

.NET Coreは、マネージソフトウェアフレームワークでオープンソースで実装されています。クロスプラットフォームを前提に考えられており、Windows/Mac/Linuxで動くアプリケーションを作成することが可能です。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

0グッド

0クリップ

投稿2021/02/28 02:28

編集2021/03/01 04:18

前提・実現したいこと

ASP.NET COREで画面表示などのタイミングで頻繁にロールの確認を行います。
複数の画面がある場合に、その都度IsInRoleAsyncを行うべきで、個々の関数に入る単位で実行するものなのでしょうか?
public async Task<IActionResult> OnGetAsync()や、
public async Task<IActionResult> OnPostAsync()単位でその都度チェックするべきでしょうか?

具体的にやろうとしていること

  • 利用ユーザ、店舗オーナ、管理者の3種類のロールがあります。
  • 店舗は、1つの店舗情報に対してイベントを複数作る事ができます。
  • 匿名または利用ユーザは、店舗情報とイベントを見る事ができます。
  • 店舗オーナは、自分の店舗とイベントの情報の変更ができますが、他オーナのは変更できません(利用ユーザと同じ権限)
  • 管理者は、全部の店舗情報、イベントの変更ができます。

例えば、
「ユーザ詳細情報」というのを表示すると、
利用ユーザの場合は自分のプロフィールが見れます。
利用ユーザの場合は、店舗情報の項目は表示されません。
店舗オーナの場合は、所有する店舗の情報が追加で表示されます。
管理者以外は他人の「ユーザ詳細情報」の表示はできません。

他にも、serIDの値を店舗オーナーの場合は、自分のUserIDのみ可。管理者ならどのIDでも可という様にロールによって可能な範囲が変わる使い方を考えています。
これらの制御をロールで行いたいのですが、毎回IsInRoleAsync()で取得をするものなのか?が知りたいです。

↓今は、こういう感じで動作させています。
イメージ説明

html

1 2 3@if (Model.OwnerFlg) 4{ 5 <div> 6 <h4>■所有店舗情報(StoreTbl)</h4> 7 <table class="table"> 8 <thead> 9 <tr> 10 <th> 11 @Html.DisplayNameFor(model => model.StoreTbls[0].StoreTblId) 12 </th> 13 <th> 14 @Html.DisplayNameFor(model => model.StoreTbls[0].OwnerTblId)

C#

1 public bool AdminFlg; 2 public bool OwnerFlg; 3 4 public async Task<IActionResult> OnGetAsync(string id) 5 { 6 AdminFlg = false; 7 OwnerFlg = false; 8 9 var user = await _userManager.GetUserAsync(User); 10 if (user == null) 11 { 12 //存在しないユーザは表示できない 13 return NotFound($"ユーザが存在しません ID = '{_userManager.GetUserId(User)}'."); 14 } 15 16 //ロール情報の取得 17 if (await _userManager.IsInRoleAsync(user, "Admin") == true) { AdminFlg = true; } 18 if (await _userManager.IsInRoleAsync(user, "Owner") == true) { OwnerFlg = true; } 19 20 //id指定が無い場合は自分を表示 21 if (id == null) { id = user.Id; } 22 23 //管理者でなければ他人の情報は見れない 24 if (AdminFlg == false) 25 { 26 if (id != user.Id) 27 { 28 return NotFound($"他人の情報は見れません ID = '{_userManager.GetUserId(User)}'."); 29 } 30 } 31 32 //ユーザのプロフィールを取得 33 App01StoreFindUser = await _context.App01StoreFindUser.FirstOrDefaultAsync(m => m.Id == id); 34 if (App01StoreFindUser == null) 35 { 36 return NotFound(); 37 } 38 39 //オーナーの場合、所有する店の一覧を表示する 40 if (OwnerFlg == true) 41 { 42 var stores = await _datacontext.StoreTbl. 43 OrderBy(stores => stores.StoreTblId).ToListAsync(); 44 }

自分で考えたり試した方法

  1. 関数(OnGetAsyncなど)の呼び出される都度、if (await _userManager.IsInRoleAsync(user, "Admin") == true) { }

を実行して正常に動作する事は確認できています。
※毎回確認は必要だが、実現方法として無駄ではないか?

  1. 認証でログインする時点(Login.cshtml.cs)で、チェックをしセッション変数に入れる。ログアウト時にセッション変数から削除する。日頃はこのセッション変数を使用するという方法。

※ログイン中に他人にロールが変更されるのは無視していいが、セッション変数が有効期限切れになった場合はどうするか?

  1. 全てのケースにおいて通過する関数があれば、そこにセッション変数がまだ有効かを確認する処理を入れ、期限切れになっていれば、IsInRoleAsync()で再取得を行い、セッション変数を再セットするという方法。

※**毎回必ず通過する関数はあるのでしょうか?**自分で確認したのですが、Program.csやStartup.csは起動時に1回だけ実行されるだけなのですね・・・

気にしていること確認したいこと

  • ロールを使用する場合、世間一般にはどういう様に実装しているのか?

ロールチェックやセッション変数の使い方が分っていても、実際の具体的な実装方法が知りたいです。

  • 「IsInRoleAsync()を毎回使う」のと、「その結果をセッション変数に入れておく」方法のコスト差(主に実行時の速度パフォーマンス)が気になります。

DBとのデータアクセスの方が遥かにコストが高いので気にする事は無いのかもしれませんが

  • リスト1つの関数内であれば、関数の先頭で取得して、AdminFlgを覚えておけば良いですが、

ページが複数あるのでそれぞれの、ユーザの情報や、店舗情報、イベントのページでGetやPostが呼ばれる毎に毎回IsInRoleAsync()で取得するのは、当然の事なのでしょうか?
これらの処理を行う共通関数を用意して、OnGetなどの各関数の先頭でuserManager、User、AdminFlg、OwnerFlgを引数にして呼ぶ・・・というよりは、これらの要素を持ったクラスを生成する?のが良いのでしょうか?

補足情報(FW/ツールのバージョンなど)

ASP.NET CORE razore

解決した内容のまとめ

  • User (ClaimsPrincipal) は必ず生成されるので、そこにあるIsInRole()を使えばよい。
  • 認証クッキーに含まれる認証チケットから生成するのでDBアクセスは行われない為、パフォーマンスは気にしなくて良い。
  • ↑上記2つに事から、コード中やhtmlの中でその都度IsInRole()で判定する方法で良い
  • ページ全体をロールの判断で制御する場合は[Authorize(Roles = "Administrator")] の方法が良い(オマケ)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

そもそも何をしたいのか分かりません。それによって答えが変わってくると思うのですが、普通にロールを使う話としてレスします。

あるページへのロールによるアクセス制限がしたいということなら、ページのクラスに Authorize 属性を付与すれば「ロールの確認(IsInRoleAsync)をするタイミング」だとか「チェックをしセッション変数に入れる」とかに悩む必要はありません。

例えば Administrator というロールがあって、Administrator ロールを持つユーザー以外のページへのアクセスを制限したいなら、そのページのクラスに以下のように属性を付与すれば OK です。お試しください。

[Authorize(Roles = "Administrator")] public class PrivacyModel : PageModel { }

Razor ASP.NET Core でのページ承認規則
https://docs.microsoft.com/ja-jp/aspnet/core/security/authorization/razor-pages-authorization

以下抜粋(翻訳がアレなので英文を載せておきます):

"注意 An AuthorizeFilter can be applied to a page model class with the [Authorize] filter attribute. For more information, see Authorize filter attribute."

ASP.NET Core でのロールベースの承認
https://docs.microsoft.com/ja-jp/aspnet/core/security/authorization/roles

残念ながら OnGetAsync() や OnPostAsync() 単位には Authorize 属性は適用できないそうです。

ASP.NET Core での単純な承認
https://docs.microsoft.com/ja-jp/aspnet/core/security/authorization/simple

上記のような話ではないなら、そもそも何がしたいのかのシナリオ・目的などを書いてください。

【追記】

ロールを使用する場合、世間一般にはどういう様に実装しているのか? ロールチェックやセッション変数の使い方が分っていても、実際の具体的な実装方法が知りたいです。

「世間一般には」というと、自分が知る限りでは上の回答に書いた通りアクセスの制限で、[Authorize(Roles = "Administrator")] というような属性を付与することです。

ロールによって同じページの中で処理を分けるというのは自分の想像の範囲を超えてました。

「IsInRoleAsync()を毎回使う」のと、「その結果をセッション変数に入れておく」方法のコスト差(主に実行時の速度パフォーマンス)が気になります。DBとのデータアクセスの方が遥かにコストが高いので気にする事は無いのかもしれませんが

IsInRoleAsync() メソッドを使うとそのたび DB にアクセスするが、それを避けるために Session を使うということを考えているのですよね。

上の回答で紹介した記事、

ASP.NET Core でのロールベースの承認
https://docs.microsoft.com/ja-jp/aspnet/core/security/authorization/roles

に書いてあるように、ClaimsPrincipal クラスの IsInRole メソッドを使ってください。以下のような感じ。

イメージ説明

質問者さんの先のスレッド https://teratail.com/questions/321876 で言いましたが、User で取得できるのは ClaimsPrincipal です。なので、OnGetAsync メソッドの中で上のようにして ClaimsPrincipal.IsInRole メソッドで判定できます。

User すなわち ClaimsPrincipal は認証クッキーに含まれる認証チケットから生成するので、いちいち DB にアクセスしに行ってません。なので「その結果をセッション変数に入れておく」うんぬんは全く考える必要はありません。

リスト1つの関数内であれば、関数の先頭で取得して、AdminFlgを覚えておけば良いですが、ページが複数あるのでそれぞれの、ユーザの情報や、店舗情報、イベントのページでGetやPostが呼ばれる毎に毎回IsInRoleAsync()で取得するのは、当然の事なのでしょうか? これらの処理を行う共通関数を用意して、OnGetなどの各関数の先頭でuserManager、User、AdminFlg、OwnerFlgを引数にして呼ぶ・・・というよりは、これらの要素を持ったクラスを生成する?のが良いのでしょうか?

上に述べた通りです。User (ClaimsPrincipal) は必ず生成されますので、それから IsInRole メソッドでロールに属するか否かを判定してください。

イメージ説明

投稿2021/02/28 04:31

編集2021/02/28 11:12
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

woodcube

2021/02/28 04:49

お世話になります。 やりたい事は、ロールによる所属によって、 ・ページを表示する内容を部分的に切り替える。 ・detailは全員アクセスできるが、editはロールによりけり、createはadminのロールのみ。 ・↑そのページへのリンクの表示も制御 といった感じです。 htmlの中でもif文で分岐したり、csのコードも途中でif文で処理が切り替わるという事です。
退会済みユーザー

退会済みユーザー

2021/02/28 04:57 編集

そのあたりのことを、質問文を編集して、できる限り詳しく、できれば具体的なサンプル・シナリオと共に追記してください。
woodcube

2021/02/28 09:08

なんどもすみません、追記しました
退会済みユーザー

退会済みユーザー

2021/02/28 11:06

お手数でした。回答欄に追記しておきます。
woodcube

2021/03/01 04:11

User (ClaimsPrincipal) にIsInRole があるのを見落としていたというか、理解が不十分で回りくどく考えていたようでした。 ASP.NETの全容の理解が全然足りてないのですね。 お恥ずかしい限りです。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問