PasswordBox и MVVM

Мы имеем следующий сценарий:

  • Пользовательский интерфейс MVVM, где пользователь может разместить свой пароль (на самом деле PasswordBox)
  • Сервер, который должен выполнить некоторую работу.
  • Сервер подключается к некоторой базе данных, требующей аутентификации

И я уже прочитал этот Вопрос о PasswordBox в MVVM

Но нет ответа, как это сделать! Просто лоты над "никогда не делайте этого".

Каков правильный способ передачи пароля? Как решить проблемы безопасности?

Нет надлежащего способа Binding для PasswordBox и Пароль не должен храниться где-то, хорошо.

Итак, что такое способ MVVM делать такие вещи?

Даже если шаблон нарушен, есть ли хороший способ достичь таких вещей?

Мысль о Func<string> для ее извлечения, но без привязки этого будет беспорядок...

Обновление То же самое для инициализации PasswordBox из хранилища паролей (надеюсь, зашифрованного). Разве это не нарушение шаблона MVVM? Пользователь не хочет вводить пароль каждый раз, когда он запускает приложение или хочет работать с базой данных, я считаю.

Ответы

Ответ 1

Лично я просто передаю весь элемент управления PasswordBox в свой LoginCommand

Я знаю, что он разрушает MVVM, потому что слой ViewModel теперь ссылается на объект, специфичный для представления, но я думаю, что в этом конкретном случае это нормально.

Итак, у меня может быть XAML, который выглядит так:

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

И a 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 не существует дольше, чем требуется пользователю для входа в систему, а фактический "пароль" - это просто текст, введенный пользователем, который может быть или не быть прав. Ключевой кейлогер может получить вам ту же информацию.)

Ответ 2

Я решил эту проблему, создав UserControl, который предоставляет свойство зависимостей SecureString, к которому можно привязать. Этот метод всегда сохраняет пароль в 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 к элементу управления к свойству Password на ViewModel. Свойство 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. Конечно, вы не должны хранить текстовую строку...

Ответ 3

в зависимости от вашего понимания 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;
    }

как вы можете видеть, ваш пароль сохраняется, и вы можете легко привязываться к нему.

Ответ 4

Оставляя эту статью в стороне - есть несколько других сообщений, связанных с этим конкретным вопросом. Вы можете добиться привязки с помощью прикрепленных свойств. Пожалуйста, смотрите: