Я сталкивался с проблемой связывания с P asswordBox
. Кажется, это угроза безопасности, но я использую шаблон MVVM, поэтому я хочу обойти это. Я нашел интересный код здесь (кто-нибудь использовал это или что-то подобное?)
http://www.wpftutorial.net/PasswordBox.html
Технически это выглядит великолепно, но я не уверен, как восстановить пароль.
У меня в основном есть свойства в моем LoginViewModel
для Username
и 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
вызывается, и если он возвращает истину, он звонит 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
.
Ответы:
Извините, но вы делаете это неправильно.
Люди должны иметь татуировку на внутренней стороне век: «
Никогда не храните пароли в виде простого текста в памяти.
Причина, по которой WPF / Silverlight
PasswordBox
не предоставляет DP дляPassword
свойства, связана с безопасностью.Если бы WPF / Silverlight сохранял DP, для
Password
этого потребовалось бы, чтобы сама среда сохраняла незашифрованный пароль в памяти. Что считается довольно неприятным вектором атаки безопасности.PasswordBox
Использует зашифрована память (своего рода) , и единственный способ получить доступ к паролю через свойства CLR.Я хотел бы предложить, чтобы при доступе к
PasswordBox.Password
свойству CLR вы воздерживались от размещения его в любой переменной или в качестве значения для любого свойства.Сохранение вашего пароля в виде обычного текста на оперативной памяти клиентского компьютера - это безопасность, нет-нет.
Так что избавься от того, что
public string Password { get; set; }
у тебя там есть.При доступе
PasswordBox.Password
просто достаньте его и отправьте на сервер как можно скорее. Не храните значение пароля и не относитесь к нему, как к любому другому тексту клиентского компьютера. Не храните пароли в виде открытого текста в памяти.Я знаю, что это нарушает шаблон MVVM, но вам никогда не следует связываться с
PasswordBox.Password
Attached DP, хранить свой пароль в ViewModel или любых других подобных махинациях.Если вы ищете решение с чрезмерной архитектурой, вот одно из них:
1. Создайте
IHavePassword
интерфейс одним методом, который возвращает открытый текст пароля.2. Попросите ваш интерфейс
UserControl
реализоватьIHavePassword
.3. Зарегистрируйте
UserControl
экземпляр в IoC как реализующийIHavePassword
интерфейс.4. Когда выполняется запрос сервера, требующий вашего пароля, позвоните в IoC для
IHavePassword
реализации и только после этого получите столь желанный пароль.Просто мой взгляд на это.
Джастин
источник
Мои 2 цента:
Однажды я разработал типичный диалог входа в систему (поля пользователя и пароля, а также кнопку «ОК») с использованием WPF и MVVM. Я решил проблему с привязкой пароля, просто передав сам элемент управления PasswordBox в качестве параметра команде, прикрепленной к кнопке «ОК». Итак, по мнению, я имел:
А во ViewModel
Execute
метод присоединенной команды был следующим:Это немного нарушает шаблон MVVM, так как теперь ViewModel знает кое-что о том, как реализован вид, но в этом конкретном проекте я мог себе это позволить. Надеюсь, это будет полезно и для кого-то.
источник
Может быть, я что-то упускаю, но кажется, что большинство этих решений слишком усложняют вещи и избавляются от безопасных практик.
Этот метод не нарушает шаблон MVVM и обеспечивает полную безопасность. Да, технически это код, но это не что иное, как «особый случай». ViewModel до сих пор не знает о реализации View, что, на мой взгляд, происходит, если вы пытаетесь передать PasswordBox в ViewModel.
Код позади! = Автоматическое нарушение MVVM. Все зависит от того, что вы делаете с этим. В этом случае мы просто вручную кодируем привязку, поэтому она считается частью реализации пользовательского интерфейса и, следовательно, в порядке.
Во ViewModel просто простое свойство. Я сделал это «только для записи», так как не должно быть необходимости извлекать его из-за пределов ViewModel по любой причине, но это не обязательно. Обратите внимание, что это SecureString, а не просто строка.
В xaml вы устанавливаете обработчик событий PasswordChanged.
В коде позади:
При использовании этого метода ваш пароль всегда остается в SecureString и, следовательно, обеспечивает максимальную безопасность. Если вы действительно не заботитесь о безопасности или вам нужен открытый текстовый пароль для нижестоящего метода, который требует его (примечание: большинство методов .NET, требующих пароль, также поддерживают параметр SecureString, поэтому вам может не понадобиться открытый текстовый пароль даже если вы так думаете), вы можете просто использовать свойство Password. Как это:
(Свойство ViewModel)
(Код позади)
Если вы хотите сохранить строгую типизацию, вы можете заменить (динамическое) приведение интерфейсом вашей ViewModel. Но на самом деле «нормальные» привязки данных также не являются строго типизированными, так что это не такая уж большая проблема.
Так что лучше всего - ваш пароль безопасен, у вашей ViewModel просто есть свойство, как у любого другого свойства, и ваш View самодостаточен без внешних ссылок.
источник
Вы можете использовать этот XAML:
И эта команда выполняет метод:
источник
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=PasswordBox}}"
(примечание: нетRelativeSource Self
).Это прекрасно работает для меня.
источник
ICommand
это реализовано в модели представления, это решение будет нарушать шаблон MVVM.Простое решение без нарушения шаблона MVVM состоит в том, чтобы ввести событие (или делегат) во ViewModel, которое собирает пароль.
В ViewModel :
public event EventHandler<HarvestPasswordEventArgs> HarvestPassword;
с этими EventArgs:
в представлении подпишитесь на событие при создании ViewModel и введите значение пароля.
В ViewModel , когда вам нужен пароль, вы можете запустить событие и получить пароль оттуда:
источник
WeakEventManager<TEventSource, TEventArgs>
чтобы избежать утечек памяти. Часто у представления не будет то же время жизни, что и у модели представления.WeakEventManager<IViewModel, EventArgs>.AddHandler(iViewModelInstance, nameof(IViewModel.Event), eventHandlerMethod);
Я провел много времени, глядя на различные решения. Мне не понравилась идея декораторов, поведение испортило интерфейс проверки, код позади ... правда?
Лучше всего придерживаться пользовательского присоединенного свойства и привязать его к своей
SecureString
модели представления. Держите его там как можно дольше. Всякий раз, когда вам понадобится быстрый доступ к простому паролю, временно преобразуйте его в незащищенную строку, используя код ниже:Убедитесь, что вы разрешаете сборщику мусора собирать ваш элемент пользовательского интерфейса, поэтому не поддавайтесь призыву использовать статический обработчик событий для
PasswordChanged
события вPasswordBox
. Я также обнаружил аномалию, когда элемент управления не обновлял пользовательский интерфейс при использованииSecurePassword
свойства для его настройки, поэтомуPassword
вместо этого я копирую пароль .И использование XAML:
Моя собственность в виде модели выглядела так:
Это
RequiredSecureString
простой пользовательский валидатор со следующей логикой:Вот, пожалуйста. Полное и проверенное чистое решение MVVM.
источник
Я отправил GIST здесь , что является Привязываемым окном для ввода пароля.
источник
ContentControl
затем вы можете просто использовать PasswordBox в качестве содержимого и стиля, которые в XAML вам подходят. Цель состоит в том,ContentControl
чтобы просто подписаться наPasswordChanged
событие и предоставить двунаправленное связываемое свойство. В целом, это 65 строк кода и в значительной степени то, что делает этот класс decorate. См. Здесь мою суть следующего gist.github.com/leidegre/c7343b8c720000fe3132Эта реализация немного отличается. Вы передаете поле пароля для привязки View через свойство в ViewModel, оно не использует никаких командных параметров. Модель представления остается неосведомленной о представлении. У меня есть проект VB vs 2010, который можно загрузить с SkyDrive. Wpf MvvM PassWordBox Пример.zip https://skydrive.live.com/redir.aspx?cid=e95997d33a9f8d73&resid=E95997D33A9F8D73!511
То, как я использую PasswordBox в Wpf MvvM-приложении, довольно упрощенно и хорошо работает для меня. Это не значит, что я думаю, что это правильный или лучший способ. Это просто реализация использования PasswordBox и шаблона MvvM.
По сути, вы создаете общедоступное свойство только для чтения, к которому представление может привязываться как PasswordBox (фактический элемент управления) Пример:
Я использую поле поддержки только для самостоятельной инициализации свойства.
Затем из Xaml вы связываете содержимое ContentControl или Контейнер элемента управления. Пример:
Оттуда у вас есть полный контроль над полем паролей. Я также использую PasswordAccessor (просто функция строки), чтобы возвращать значение пароля при входе в систему или для чего-либо еще, для чего вы хотите пароль. В примере у меня есть открытое свойство в универсальной объектной модели пользователя. Пример:
В объекте пользователя свойство строки пароля доступно только для чтения без какого-либо резервного хранилища, оно просто возвращает пароль из PasswordBox. Пример:
Затем в ViewModel я проверяю, что Accessor создан и установлен в свойство PasswordBox.Password 'Пример:
Когда мне нужна строка «Пароль», скажем, для входа в систему, я просто получаю свойство «Пароль объекта пользователя», которое действительно вызывает функцию, чтобы получить пароль и вернуть его, тогда фактический пароль не сохраняется объектом пользователя. Пример: будет в ViewModel
Это должно сделать это. ViewModel не требует никаких знаний об элементах управления View. Представление просто привязывается к свойству в ViewModel, ничем не отличающимся от представления, связывающегося с изображением или другим ресурсом. В этом случае этот ресурс (свойство) просто является пользовательским контролем. Это позволяет проводить тестирование, поскольку ViewModel создает и владеет свойством, а свойство не зависит от представления. Что касается безопасности, я не знаю, насколько хороша эта реализация. Но при использовании функции значение не сохраняется в самом свойстве, просто доступ к нему осуществляется.
источник
Чтобы решить проблему OP, не нарушая MVVM, я бы использовал конвертер пользовательских значений и оболочку для значения (пароля), которое необходимо получить из поля пароля.
В представлении модель:
Поскольку модель представления использует
IWrappedParameter<T>
, она не должна иметь никаких знанийPasswordBoxWrapper
ни оPasswordBoxConverter
. Таким образом, вы можете изолироватьPasswordBox
объект от модели представления и не нарушать шаблон MVVM.По мнению:
источник
Хотя я согласен с тем, что важно избегать хранения пароля в любом месте, мне все еще нужна возможность создания экземпляра модели представления без представления и выполнения моих тестов против него.
Решение, которое работало для меня, состояло в том, чтобы зарегистрировать функцию PasswordBox.Password в модели представления и заставить модель представления вызывать ее при выполнении кода входа в систему.
Это делает означает строку кода в коде представления.
Итак, в моем Login.xaml у меня есть
а в Login.xaml.cs у меня есть
тогда в LoginViewModel.cs я определил PasswordHandler
и когда требуется вход в систему, код вызывает обработчик, чтобы получить пароль из представления ...
Таким образом, когда я хочу протестировать модель представления, я могу просто установить PasswordHandler на анонимный метод, который позволяет мне предоставлять любой пароль, который я хочу использовать в тесте.
источник
Я решил добавить свое решение в микс, так как это такая распространенная проблема ... и наличие большого количества вариантов всегда хорошо.
Я просто завернула
PasswordBox
вUserControl
и реализовал,DependencyProperty
чтобы иметь возможность связывать. Я делаю все от меня зависящее, чтобы избежать сохранения любого открытого текста в памяти, поэтому все делается через aSecureString
иPasswordBox.Password
свойство. Во времяforeach
цикла каждый персонаж действительно выставляется, но это очень кратко. Честно говоря, если вы беспокоитесь о том, что ваше приложение WPF может быть скомпрометировано из-за этого краткого разоблачения, у вас есть более серьезные проблемы с безопасностью, которые следует решать.Прелесть этого в том, что вы не нарушаете никаких правил MVVM, даже «пуристических», поскольку это
UserControl
так, поэтому разрешено иметь кодовый код. Когда вы используете его, вы можете иметь чистую связь междуView
ViewModel
вами и безVideModel
знания какой-либо частиView
или источника пароля. Просто убедитесь, что вы привязаны кSecureString
своемуViewModel
.BindablePasswordBox.xaml
BindablePasswordBox.xaml.cs (Версия 1 - двусторонняя привязка не поддерживается.)
Использование версии 1:
BindablePasswordBox.xaml.cs (версия 2 - имеет поддержку двусторонней привязки.)
Использование версии 2:
источник
if (Password != secure)
что всегда будет ложным, так как SecureString не переопределяет равно. Есть предположения?Вы можете сделать это с прикрепленным свойством, посмотрите это. PasswordBox с MVVM
источник
Я использовал этот метод и передал поле пароля, хотя это нарушает MVVM, это было важно для меня, потому что я использовал элемент управления контентом с шаблоном данных для моего входа в систему в моей оболочке, которая является сложной средой оболочки. Таким образом, доступ к коду позади оболочки был бы дерьмом.
Насколько я знаю, передача пароля должна быть такой же, как и контроль доступа из кода. Я согласен с паролями, не храню в памяти и т.д. В этой реализации у меня нет свойства для пароля в модели представления.
Кнопка Команда
ViewModel
источник
Мне обе эти вещи кажутся неправильными:
PasswordBox
качестве параметра команды в ViewModelПередача SecurePassword (экземпляр SecureString), как описано Стивом в CO, кажется приемлемой. я предпочитаю
Behaviors
кодировать, и у меня также было дополнительное требование, чтобы иметь возможность сбросить пароль из viewmodel.Xaml (
Password
это свойство ViewModel):Поведение:
источник
Для полных новичков, как я, вот полный рабочий пример того, что
Konamiman
предложено выше. БлагодаряKonamiman
.XAML
ViewModel
источник
Это прикрепленное свойство . Этот тип свойства может применяться к любому виду
DependencyObject
, а не только к типу, в котором оно объявлено. Таким образом, даже если он объявлен вPasswordHelper
статическом классе, он применяется кPasswordBox
на котором вы его используете.Чтобы использовать это прикрепленное свойство, вам просто нужно привязать его к
Password
свойству в вашей ViewModel:источник
Я сделал как:
XAML:
C #:
Меня устраивает!
источник
Как упоминалось ранее, VM не должна знать о View, но передача всего PasswordBox выглядит как самый простой подход. Поэтому, возможно, вместо приведения переданного параметра к PasswordBox используйте Reflection, чтобы извлечь из него свойство Password. В этом случае VM ожидает некоторый контейнер паролей со свойством Password (я использую RelayCommands из MVMM Light-Toolkit):
Это можно легко проверить с помощью анонимного класса:
источник
В Windows универсальное приложение
Вы можете использовать этот код со свойством «Пароль» и связывание с modelView
источник
Для любого, кто знает о рисках, связанных с этой реализацией, для синхронизации пароля с вашей ViewModel просто добавьте Mode = OneWayToSource .
XAML
источник
OneWayToSource
?Вот мой взгляд на это:
Использование присоединенного свойства для привязки пароля сводит на нет цель его защиты. Свойство Password поля пароля не может быть привязано по какой-либо причине.
Передача поля пароля в качестве параметра команды сделает ViewModel осведомленным об элементе управления. Это не будет работать, если вы планируете сделать вашу ViewModel кроссплатформенную многоразового использования. Не информируйте вашу виртуальную машину о вашем View или других элементах управления.
Я не думаю, что введение нового свойства, интерфейса, подписка на события, измененные паролем, или любые другие сложные вещи необходимы для простой задачи предоставления пароля.
XAML
Код позади - использование кода сзади не обязательно нарушает MVVM. Пока вы не вкладываете в это бизнес-логику.
ViewModel
источник
Вы найдете решение для PasswordBox в примере приложения ViewModel проекта WPF Application Framework (WAF) .
Однако Джастин прав. Не передавайте пароль как обычный текст между View и ViewModel. Вместо этого используйте SecureString (см. MSDN PasswordBox).
источник
Я использовал проверку подлинности, за которой последовала подпрограмма, вызываемая классом-посредником для View (которая также реализует проверку подлинности), чтобы записать пароль для класса данных.
Это не идеальное решение; однако это исправило мою проблему невозможности переместить пароль.
источник
Я использую сжатое MVVM-дружественное решение, которое еще не было упомянуто. Сначала я называю PasswordBox на XAML:
Затем я добавляю единственный вызов метода в конструктор представления:
И это все. Модель представления получит уведомление, когда оно присоединено к представлению через DataContext, и другое уведомление, когда оно отсоединено. Содержимое этого уведомления настраивается через лямбды, но обычно это просто вызов метода или метода для модели представления, передавая проблемный элемент управления в качестве параметра.
Это очень легко сделать MVVM-дружественным, если вместо дочерних элементов управления использовать интерфейс представления.
Приведенный выше код опирается на вспомогательный класс, опубликованный в моем блоге.
источник
Я потратил целую вечность, пытаясь заставить это работать. В конце концов, я сдался и просто использовал PasswordBoxEdit от DevExpress.
Это самое простое решение, так как оно позволяет связывать без каких-либо ужасных трюков.
Решение на сайте DevExpress
Для справки, я никак не связан с DevExpress.
источник
;) легко!
источник
Это очень просто. Создайте другое свойство для пароля и свяжите это с TextBox
Но все операции ввода выполняются с фактическим свойством пароля
приватная строка _Password;
публичная строка Password {get {return _Password; }
источник
ну мой ответ более прост только в шаблоне MVVM
в классе viewmodel
свойство пароля выигравшего PasswordBox или WatermarkPasswordBox, предоставляемого XCeedtoolkit, генерирует RoutedEventArgs, чтобы вы могли связать его.
сейчас в формате xmal
или
источник
Отправьте
SecureString
модель представления, используя прикрепленное поведение иICommand
В реализации кода нет ничего плохого при реализации MVVM. MVVM - это архитектурный шаблон, целью которого является отделение представления от модели / бизнес-логики. MVVM описывает, как достичь этой цели воспроизводимым способом (схема). Его не волнуют детали реализации, например, как вы структурируете или реализуете представление. Он просто рисует границы и определяет, что такое представление, модель представления и что такое модель с точки зрения терминологии этого шаблона.
MVVM не заботится о языке (XAML или C #) или компиляторе (
partial
классах). Независимость от языка является обязательной характеристикой шаблона проектирования - она должна быть независимой от языка.Однако у кода есть некоторые недостатки, такие как усложнение понимания вашей логики пользовательского интерфейса, когда она широко распространена между XAML и C #. Но наиболее важная реализация логики или объектов пользовательского интерфейса, таких как шаблоны, стили, триггеры, анимация и т. Д. В C #, очень сложна и уродлива / менее читаема, чем при использовании XAML. XAML - это язык разметки, который использует теги и вложенность для визуализации иерархии объектов. Создание пользовательского интерфейса с использованием XAML очень удобно. Хотя бывают ситуации, когда вы можете выбрать логику пользовательского интерфейса в C # (или коде). Обработка
PasswordBox
- один из примеров.По этой причине обработка
PasswordBox
кода в коде путем обработкиPasswordBox.PasswordChanged
, не является нарушением шаблона MVVM.Явным нарушением будет передача управления (
PasswordBox
) модели представления. Многие решения рекомендовать , например, лавровый передавая экземпляр класса ,PasswordBox
какICommand.CommandParameter
в модель представления. Очевидно, очень плохая и ненужная рекомендация.Если вы не заботитесь об использовании C #, а просто хотите, чтобы ваш файл кода был чистым или просто хотите инкапсулировать логику поведения / пользовательского интерфейса, вы всегда можете использовать вложенные свойства и реализовать присоединенное поведение.
В отличие от печально известного широко распространенного помощника, который обеспечивает привязку к простому текстовому паролю (очень плохой анти-шаблон и угроза безопасности), это поведение использует
ICommand
пароль для отправки пароляSecureString
к модели представления всякий раз, когдаPasswordBox
поднимаетсяPasswordBox.PasswordChanged
событие.MainWindow.xaml
ViewModel.cs
PasswordBox.cs
источник