web-dev-qa-db-ja.com

PasswordBoxとMVVM

次のシナリオがあります。

  1. ユーザーが自分のパスワードを入力できるMVVMユーザーインターフェイス(実際にはPasswordBox
  2. いくつかの作業を行うサーバー
  3. サーバーは、認証が必要なデータベースに接続します

そして、私はすでにこれを読んでいます MVVMのPasswordBoxに関する質問

しかし、その方法については答えがありません! 「決してそんなことはしない」だけではありません。

パスワードを渡す正しい方法は何ですか?セキュリティの問題を解決する方法は?

BindingからPasswordBoxへの適切な方法はなく、パスワードはどこかに保存されません。

それで、そのようなことをするMVVMの方法は何ですか?

パターンが壊れていても、そのようなことを達成するための良い方法はありますか?

それを取得するためのFunc<string>の考えですが、Bindingがないと、これは混乱します...

Update(うまくいけば暗号化された)パスワードストアからPasswordBoxを初期化する場合も同じです。それはMVVMパターンを壊していませんか?ユーザーは、アプリケーションを起動するたびにパスワードを入力したり、私が信じているデータベースで作業したりすることを望んでいません。

18
Mare Infinitus

個人的には、PasswordBoxコントロール全体をLoginCommandに渡すだけです。

ViewModelレイヤーがView固有のオブジェクトを参照するようになったので、MVVMが壊れることはわかっていますが、この特定のケースでは問題ないと思います。

したがって、次のようなXAMLを使用している可能性があります。

<Button Content="Login" 
        Command="{Binding LoginCommand}" 
        CommandParameter="{Binding ElementName=MyPasswordBox}" />

そして、次のようなことを行うLoginCommand

private void Login(object obj)
{
    PasswordBox pwBox = obj as PasswordBox;

    SomeBlackBoxClass.ValidatePassword(UserName, pwBox.Password);
}

値に対して何らかの暗号化アルゴリズムを実行し、その値のハッシュをユーザーのパスワードのハッシュと比較することもできると思います

private void Login(object obj)
{
    PasswordBox pwBox = obj as PasswordBox;
    var encryptedPassword = SomeLibrary.EncryptValue(pwBox.Password, someKey);

    if (encryptedPassword == User.EncryptedPassword)
        // Success
}

私はPasswordBoxコントロールやセキュリティの専門家ではありませんが、ユーザーのパスワードをプレーンテキストでアプリケーション内のメモリのどこにも保存したくないことは知っています。

(技術的には、プレーンテキストとしてPasswordBox.Passwordに保存されます-必要に応じて Snoop のようなものを使用してこれを確認できます-ただし、通常、PasswordBoxはユーザーが必要とする時間より長く存在しませんログインするために、実際の「パスワード」はユーザーが入力したテキストであり、正しい場合と正しくない場合があります。キーロガーが同じ情報を取得する可能性があります。)

38
Rachel

バインドできるSecureString依存関係プロパティを公開するUserControlを作成することで、この問題を解決しました。このメソッドは、パスワードを常にSecureStringに保持し、MVVMを「破壊」しません。

UserControl

XAML

<UserControl x:Class="Example.PasswordUserControl"
         xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.Microsoft.com/expression/blend/2008"
         mc:Ignorable="d"
         d:DesignHeight="300" d:DesignWidth="300">
    <Grid>       
        <PasswordBox Name="PasswordBox" />
    </Grid>
</UserControl>

CS

public partial class PasswordUserControl : UserControl
{
    public SecureString Password
    {
        get { return (SecureString) GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }
    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.Register("Password", typeof(SecureString), typeof(UserCredentialsInputControl),
            new PropertyMetadata(default(SecureString)));


    public PasswordUserControl()
    {
        InitializeComponent();

        // Update DependencyProperty whenever the password changes
        PasswordBox.PasswordChanged += (sender, args) => {
            Password = ((PasswordBox) sender).SecurePassword;
        };
    }
}

使用例

コントロールの使用は非常に簡単です。コントロールのパスワードDependencyPropertyをViewModelのPasswordプロパティにバインドするだけです。 ViewModelのPasswordプロパティはSecureStringである必要があります。

<controls:PasswordUserControl Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

バインディングのModeおよびUpdateSourceトリガーを最適なものに変更します。

プレーンテキストのパスワードが必要な場合は、次のページでSecureStringと文字列を変換する適切な方法について説明します。 http://blogs.msdn.com/b/fpintos/archive/2009/06/12/how -to-properly-convert-securestring-to-string.aspx 。もちろん、プレーンテキストの文字列を保存するべきではありません...

5
DinoM

mvvmの理解に応じて(私の方法では、コードビハインドが許可される場合があります)

だから私はPasswordBoxと名前付きTextBlockを作成します

XAML

<PasswordBox Height="23" Width="156" PasswordChar="*" PasswordChanged="pwBoxUser_PasswordChanged"/>
<TextBlock Height="1" Width="1" Name="MD5pw" Text="{Binding Passwort, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}" VerticalAlignment="Top" />

コードビハインド

    private void pwBoxUser_PasswordChanged(object sender, RoutedEventArgs e)
    {
        var pBox =sender as PasswordBox;
        string blank=pBox.Password;

        //to crypt my blank Password
        var sMD5 = myMD5.toMD5(blank); //implement your crypt logic here
        blank ="";

        MD5pw.Text = sMD5;
    }

あなたがあなたのパスワードが保存されているのを見ることができるようにそしてあなたはそれに簡単にバインドすることができます

1
WiiMaxx

その記事はさておき、この特定の質問に関連する他の投稿がいくつかあります。添付プロパティを使用してバインディングを実現できます。参照してください:

  1. この質問は PasswordBox Binding の複製だと思います
  2. 上記の投稿は- http://www.wpftutorial.net/PasswordBox.html を指しています