へのバインディングで問題が発生しましたPasswordBox
。セキュリティ リスクのようですが、MVVM パターンを使用しているため、これを回避したいと考えています。ここで興味深いコードを見つけました (これまたは同様のものを使用した人はいますか?)
http://www.wpftutorial.net/PasswordBox.html
技術的には素晴らしいように見えますが、パスワードを取得する方法がわかりません。
LoginViewModel
基本的に、 forUsername
とにはプロパティがありPassword
、Username
であるため問題なく動作していますTextBox
。
上記のコードを記載通りに使用し、これを入力しました
<PasswordBox ff:PasswordHelper.Attach="True"
ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>
PasswordBox
を として持っていたときにTextBox
、Binding Path=Password
のプロパティLoginViewModel
が更新されました。
Command
私のコードは非常にシンプルで、基本的にの がありますButton
。これを押すとCanLogin
が呼び出され、true が返された場合は が呼び出されますLogin
。ここ
で のプロパティをチェックしていますが、うまく機能していることがわかりますUsername
。
私Login
は私のサービスに送信しUsername
、私のデータが含まれていPassword
ますが、Username
View
Password
Null|Empty
private DelegateCommand loginCommand;
public string Username { get; set; }
public string Password { get; set; }
public ICommand LoginCommand
{
get
{
if (loginCommand == null)
{
loginCommand = new DelegateCommand(
Login, CanLogin );
}
return loginCommand;
}
}
private bool CanLogin()
{
return !string.IsNullOrEmpty(Username);
}
private void Login()
{
bool result = securityService.IsValidLogin(Username, Password);
if (result) { }
else { }
}
私がやっているのはこれです
<TextBox Text="{Binding Path=Username, UpdateSourceTrigger=PropertyChanged}"
MinWidth="180" />
<PasswordBox ff:PasswordHelper.Attach="True"
ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>
私は を持っていますTextBox
が、これは問題ありません。しかし、私の にはViewModel
がPassword
空です。
何か間違ったことをしているのでしょうか、それとも手順が抜けているのでしょうか?
ブレークポイントを設定すると、確かにコードは静的ヘルパー クラスに入りますが、 では更新されませPassword
んViewModel
。
ベストアンサー1
何か見落としているのかもしれませんが、これらのソリューションのほとんどは物事を複雑にしすぎて、安全な慣行を廃止しているように思われます。
この方法は MVVM パターンに違反せず、完全なセキュリティを維持します。技術的にはコード ビハインドですが、これは「特別なケース」バインディングに過ぎません。ViewModel はまだ View 実装を認識していませんが、PasswordBox を ViewModel に渡そうとしている場合は認識していると思います。
コード ビハインド != 自動 MVVM 違反。すべては、それをどう使うかによって決まります。この場合、バインディングを手動でコーディングしているだけなので、すべて UI 実装の一部とみなされ、問題ありません。
ViewModel では、単純なプロパティです。何らかの理由で ViewModel の外部から取得する必要はないため、これを「書き込み専用」にしましたが、必ずしもそうする必要はありません。これは単なる文字列ではなく、SecureString であることに注意してください。
public SecureString SecurePassword { private get; set; }
xaml では、PasswordChanged イベント ハンドラーを設定します。
<PasswordBox PasswordChanged="PasswordBox_PasswordChanged"/>
コードビハインドでは:
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (this.DataContext != null)
{ ((dynamic)this.DataContext).SecurePassword = ((PasswordBox)sender).SecurePassword; }
}
このメソッドを使用すると、パスワードは常に SecureString 内に保持されるため、最大限のセキュリティが確保されます。セキュリティをまったく気にしない場合、または、クリア テキスト パスワードを必要とするダウンストリーム メソッドでクリア テキスト パスワードが必要な場合 (注: パスワードを必要とするほとんどの .NET メソッドは SecureString オプションもサポートしているため、必要だと思っていても、実際にはクリア テキスト パスワードは必要ではない場合があります)、代わりに Password プロパティを使用できます。次のようになります。
(ViewModel プロパティ)
public string Password { private get; set; }
(コードビハインド)
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (this.DataContext != null)
{ ((dynamic)this.DataContext).Password = ((PasswordBox)sender).Password; }
}
厳密に型付けされたままにしたい場合は、(動的) キャストを ViewModel のインターフェースに置き換えることができます。ただし、実際には、「通常の」データ バインディングも厳密に型付けされていないため、それほど大きな問題ではありません。
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (this.DataContext != null)
{ ((IMyViewModel)this.DataContext).Password = ((PasswordBox)sender).Password; }
}
つまり、何よりも、パスワードは安全で、ViewModel には他のプロパティと同じようにプロパティがあり、View は外部参照を必要とせずに自己完結型になります。