前提・実現したいこと
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 }
自分で考えたり試した方法
- 関数(OnGetAsyncなど)の呼び出される都度、if (await _userManager.IsInRoleAsync(user, "Admin") == true) { }
を実行して正常に動作する事は確認できています。
※毎回確認は必要だが、実現方法として無駄ではないか?
- 認証でログインする時点(Login.cshtml.cs)で、チェックをしセッション変数に入れる。ログアウト時にセッション変数から削除する。日頃はこのセッション変数を使用するという方法。
※ログイン中に他人にロールが変更されるのは無視していいが、セッション変数が有効期限切れになった場合はどうするか?
- 全てのケースにおいて通過する関数があれば、そこにセッション変数がまだ有効かを確認する処理を入れ、期限切れになっていれば、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")] の方法が良い(オマケ)
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/02/28 04:49
退会済みユーザー
2021/02/28 04:57 編集
2021/02/28 09:08
退会済みユーザー
2021/02/28 11:06
2021/03/01 04:11