MVVMでPasswordBoxにバインドする方法 質問する

MVVMでPasswordBoxにバインドする方法 質問する

へのバインディングで問題が発生しましたPasswordBox。セキュリティ リスクのようですが、MVVM パターンを使用しているため、これを回避したいと考えています。ここで興味深いコードを見つけました (これまたは同様のものを使用した人はいますか?)

http://www.wpftutorial.net/PasswordBox.html

技術的には素晴らしいように見えますが、パスワードを取得する方法がわかりません。

LoginViewModel基本的に、 forUsernameとにはプロパティがありPasswordUsernameであるため問題なく動作していますTextBox

上記のコードを記載通りに使用し、これを入力しました

<PasswordBox ff:PasswordHelper.Attach="True"
    ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>

PasswordBoxを として持っていたときにTextBoxBinding Path=PasswordのプロパティLoginViewModelが更新されました。

Command私のコードは非常にシンプルで、基本的にの がありますButton。これを押すとCanLoginが呼び出され、true が返された場合は が呼び出されますLogin。ここ
で のプロパティをチェックしていますが、うまく機能していることがわかりますUsername

Loginは私のサービスに送信しUsername、私のデータが含まれていPasswordますが、UsernameViewPasswordNull|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が、これは問題ありません。しかし、私の にはViewModelPassword空です。

何か間違ったことをしているのでしょうか、それとも手順が抜けているのでしょうか?

ブレークポイントを設定すると、確かにコードは静的ヘルパー クラスに入りますが、 では更新されませPasswordViewModel

ベストアンサー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 は外部参照を必要とせずに自己完結型になります。

おすすめ記事