引き続き、Microsoft.TeamFoundation.MVVM
名前空間を使って作る、WPFアプリの話です。
今回は、GenericPrincipalを使った認証と承認を行い、画面の表示を制限してみました。
2015/12/10 追記 ここから
公式Blogに以下の記事が掲載されましたので、Microsoft.TeamFoundation.MVVM
の使用前に記事を確認してみてください。
Microsoft.TeamFoundation.MVVM 名前空間の利用について - Visual Studio サポート チーム blog - Site Home - MSDN Blogs
2015/12/10 追記 ここまで
環境
仕様
以下の通りです。
- ログイン画面でユーザー名を入力
- 管理者ユーザーの場合、全部のボタンが表示
- それ以外の場合、一部のボタンの表示を制限
なお、ボタン表示については、
の2パターンを用意し、どのように表示が異なるのかを試してみました。
ログイン画面
View
LoginView.xamlに実装します。
定型的なところ
以下の項目を追加しますが、定型なので省略します。
- Window要素
- Window.DataContext
- Window.Resources
PasswordBoxへのデータバインディング
今回、ユーザー名の入力欄にはPasswordBoxを使いました(WPFでPasswordBoxを使ってみたかっただけで、特に深い意味はありません)。
PasswordBoxには以下のデータバインディングを行います。
- コマンド (
Path
で指定) - Enterキーを押した時にコマンドを実行 (
Key
で指定) - コマンドに渡すパラメータの指定 (
CommandParameter
で指定)
<PasswordBox Grid.Row="1" Name="passwordBox"> <PasswordBox.InputBindings> <KeyBinding Command="{Binding Path=LoginCommand}" Key="Enter" CommandParameter="{Binding ElementName=passwordBox}"/> </PasswordBox.InputBindings> </PasswordBox>
参考:
- c# - WPF: Command for TextBox which fires up when we hit Enter Key on It? - Stack Overflow
- c# - How to bind to a PasswordBox in MVVM - Stack Overflow
起動時にPasswordBoxへフォーカスを当てる
以下を参考にGridへと設定しました。
WPFは初期フォーカスをXamlで設定できるでやんの。 - ABCの海岸で
<Grid FocusManager.FocusedElement="{Binding ElementName=passwordBox}">
ViewModel
LoginViewModel.cs に実装します。
PasswordBoxの値の参照
今回はViewにて、PasswordBoxのCommandParameter
にPasswordBoxの値を設定するようにしています。
そのため、ViewModelのCommandの実装部分、ExecuteLoginCommand
メソッドにて、以下のような感じで参照できます。
private void ExecuteLoginCommand(object x) { var passwordBox = x as System.Windows.Controls.PasswordBox; var value = passwordBox.Password }
なお、PasswordBoxのPassword
プロパティについては、以下にある通り直接な参照は控えたほうがいいかもしれません。
- c# - How to bind to a PasswordBox in MVVM - Stack Overflow
- PasswordBox.Password プロパティ (System.Windows.Controls) - MSDN
- PasswordBoxコントロールのPasswordプロパティが依存関係プロパティとして実装されていない理由 - Yuya Yamaki’s blog
ただ、SecurePasswordのプロパティの扱いは少々面倒な上、今回はパスワードではなくユーザー名を渡しているだけなので、手抜きでPasswordプロパティの参照にしています。
ユーザーに対するRoleの割り当て
PasswordBoxのユーザー名に応じてRoleを割り当てます。そのRoleを元に、LoggedinViewの表示をLoggedinViewModelで制限します。
MSDNにある通り、GenericPrincipal オブジェクトと GenericIdentity オブジェクトを作成して、CurrentPrincipalに割り当てます。
方法 : GenericPrincipal オブジェクトと GenericIdentity オブジェクトを作成する - MSDN
var identity = new GenericIdentity(passwordBox.Password); var principal = new GenericPrincipal(identity, GetRoles(passwordBox.Password)); Thread.CurrentPrincipal = principal;
ログイン後の画面
View
LoggedinView.xaml に実装します。
XAMLには
- PasswordBoxで入力したユーザー名を表示するため、TextBlockのTextプロパティ
- ButtonのCommandプロパティ
- ButtonのVisibilityプロパティ
を記述します。
<TextBlock Grid.Row="0" Text="Loggedin User:"/> <TextBlock Grid.Row="1" Text="{Binding Path=LoggedinUser}"/> <Button Grid.Row="2" Content="All by RelayCommand" Command="{Binding Path=AllCommand}"/> <Button Grid.Row="3" Content="Limit by RelayCommand" Command="{Binding Path=LimitCommand}"/> <Button Grid.Row="4" Content="All by Visibility" Visibility="{Binding Path=VisibilityAll}"/> <Button Grid.Row="5" Content="Limit by Visibility" Visibility="{Binding Path=VisibilityLimit}"/>
ViewModel
LoggedinViewModel.csに実装します。
PasswordBoxに入力したユーザー名の取得
以下の記事のコメントにもある通り、Thread.CurrentPrincipal.Identity.Name
には認証されていなくても値が設定されていることがあるため、認証されているかを判断した上でユーザー名を取得します。
リッチクライアントとロールベースセキュリティ - Kazzzの日記
if (_loggedinUser == null && Thread.CurrentPrincipal.Identity.IsAuthenticated) { _loggedinUser = Thread.CurrentPrincipal.Identity.Name; }
Commandプロパティで、RelayCommandオブジェクトによる表示制御
以下の感じのようなコードで、RelayCommand
のコンストラクタの第二引数にboolを渡すことで、Viewにおけるボタン表示のenabled/disabledを切り替えています。
Roleに属しているかは、Thread.CurrentPrincipal.IsInRole("Role1");
で判断しています。
private ICommand _allCommand; public ICommand AllCommand { get { if (_allCommand == null) { _allCommand = new Microsoft.TeamFoundation.MVVM.RelayCommand(ExecuteAllCommand, CanExecuteAllCommand); } return _allCommand; } } private void ExecuteAllCommand(object x) { } private bool CanExecuteAllCommand(object x) { // 認証されて`Role1`に属していたらtrue return Thread.CurrentPrincipal.Identity.IsAuthenticated && Thread.CurrentPrincipal.IsInRole("Role1"); }
Visibilityプロパティによる制御
そのままです。
public System.Windows.Visibility VisibilityAll { get { // 認証されて`Role1`に属していたらVisible, そうでなければHidden if (Thread.CurrentPrincipal.Identity.IsAuthenticated && Thread.CurrentPrincipal.IsInRole("Role1")) { return System.Windows.Visibility.Visible; } else { return System.Windows.Visibility.Hidden; } } }
作成した画面イメージ
ログイン画面
管理者ユーザーの場合
全てのボタンが見えています。
その他の場合
RelayCommandの場合はDisabledになっているだけですが、VIsibilityはHideになっています。
ソースコード
GitHubにあげておきました。
CSharp-Sample/MVVMApp/GenericPrincipalMVVM at master · thinkAmi/CSharp-Sample · GitHub
参考資料
ロールベースセキュリティ
- ロール ベース セキュリティ - MSDN
- @IT:インサイド .NET Framework [改訂版]第10回 ロールベース・セキュリティ
- 10 行でズバリ !! ロール ベース セキュリティ (C#) in C#
PasswordBox
書籍
VB.NETとWindowsFormがメインですが、.NET Frameworkの認証と承認についてまとまっており、とても参考になりました。
Visual Basic 2008 逆引きレシピ[Windows アプリケーション編] (PROGRAMMER’S RECiPE)
- 作者: 中垣健志,藤田聡
- 出版社/メーカー: 翔泳社
- 発売日: 2009/02/24
- メディア: 単行本(ソフトカバー)
- 購入: 3人 クリック: 29回
- この商品を含むブログ (6件) を見る