MVVM-də bir parol ilə əlaqə qurmaq

PasswordBox üçün məcburi bir problemim var. Bu təhlükəsizlik təhdidi kimi görünür, amma MVVM modelini istifadə edirəm, buna görə də bu barədə danışmaq istəyirəm. Burada maraqlı bir kod tapdım (hər kəs bu və ya bir şeydən istifadə edib mi?)

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

Texniki cəhətdən gözəl görünür, amma şifrəni necə əldə etmək üçün əmin deyiləm.

Mən əsasən LoginViewModel istifadəçi UsernamePassword . Username işləyir və bir TextBox kimi işləyir.

Yuxarıda göstərilən kodu istifadə etdilər və daxil oldum

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

PasswordBox TextBoxBinding Path=Password LoginViewModel , mənim LoginViewModel əmlak yeniləndi.

Mənim kodum çox sadədir, əsasən mənim Button üçün bir Command var. Mən onu tıkladığımda, CanLogin , əgər doğru CanLogin , Login .
Gördüyünüz kimi, burada mənim "Adı" əmlakını yoxlayıram.

Girişdə xidmətimə bir UsernamePassword göndərir, Username mənim View məlumatlar ehtiva edir, amma 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 { } } 

Mən bunu edirəm

 <TextBox Text="{Binding Path=Username, UpdateSourceTrigger=PropertyChanged}" MinWidth="180" /> <PasswordBox ff:PasswordHelper.Attach="True" ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/> 

Məndə TextBox , bu problem deyil, mənim ViewModel boşdur.

Səhv bir şey edirəmmi və ya bir addımı atmırmı?

Bir kəsmə nöqtəsi qoyuram və əlbəttə ki, kod statik köməkçi sinif təqdim edir, amma mənim ViewModelPassword heç vaxt ViewModel .

190
27 сент. mark qurdu smith 27 sep. 2009-09-27 19:34 '09 da 19:34 'da 2009-09-27 19:34
@ 27 cavab

Bağışlayın, ancaq səhv edirsiniz.

İnsanlar göz qapaqlarına toxunaraq, aşağıdakı təhlükəsizlik qayda olmalıdır:
Sadə mətn parollarını yaddaşda saxlamayın.

WPF / Silverlight PasswordBox Şifrənin əmlakı üçün təhlükəsizlik təmin etməməsi səbəbi təhlükəsizlik ilə bağlıdır.
WPF / Silverlight bir parol üçün DP-ni saxlamaq məcburiyyətində qaldıqda, bu çərçivənin şifrənin özü yaddaşda şifrələnməməsini tələb edirdi. Bu, olduqca mürəkkəb bir təhlükəsizlik hücumu vektoru hesab olunur. PasswordBox şifrəli yaddaş (sıralama) istifadə edir və CLR mülkiyyəti parol daxil olmaq üçün yeganə yoldur.

CLB PasswordBox.Password sisteminə daxil olmağınızda hər hansı bir dəyişənə və ya hər hansı bir əmlak üçün dəyərə yerləşdirilməməyə mane olursunuz.
Şifrənizi müştəri RAM-də mətn şəklində saxlamağınız təhlükəsizdir.
Beləliklə, orada qaldığınız bu "ictimai şifrə Şifrə {get;

PasswordBox.Password paroluna daxil olduqda, onu əldə edin və mümkün qədər tez serverə göndərin. Şifrənin dəyərini saxlamayın və onu kompüterin digər mətnləri ilə eyni qaydada müalicə etməyin. Təmiz mətn parollarını saxlamayın.

Budur ki, bu MVVM modelini pozur, ancaq ParolBox.Password Attached DP-yə heç bir zaman əlavə edilməməlidir, parolunuzu ViewModel-də və ya digər oxşar saxtakarlıqlarda saxlamalısınız.

Artıq bir arxitektura həll axtarırsınızsa, burada birdir:
1. Bir mətn parolunu qaytaran bir metodu istifadə edərək IHavePassword interfeysini yaradın.
2. IHavePassword interfeysini həyata keçirmək üçün UserControl müraciət edin.
3. IcoC'yi IHavePassword interfeysinin tətbiqi kimi UserControl nümunəsini qeyd edin.
4. Şifrənizi tələb edən bir server sorğusu tələb olunduqda, IHavePassword proqramını həyata keçirmək üçün IoC-ə zəng edin və yalnız ən çox istənilən şifrəni əldə edin.

Yalnız götür.

- Justin

131
29 сент. Cavab JustinAngel 29 sep tərəfindən verilir . 2009-09-29 18:31 '09 da 18:31 'də 2009-09-29 18:31

Mənim 2 qəpik:

WPF və MVVM istifadə edərək tipik bir giriş informasiya qutusunu (istifadəçi və parol sahələri, üstəgəl "OK" düyməsini) inkişaf etdirdim. Parolu bağlama problemini sadəcə PasswordBox nəzarətini OK düyməsinə əlavə olunan əmrə bir parametr olaraq keçərək həll etdim. Beləliklə, məndə idi:

 <PasswordBox Name="txtPassword" VerticalAlignment="Top" Width="120" /> <Button Content="Ok" Command="{Binding Path=OkCommand}" CommandParameter="{Binding ElementName=txtPassword}"/> 
border=0

Və ViewModeldə əlavə əmrin Execute üsulu belə idi:

 void Execute(object parameter) { var passwordBox = parameter as PasswordBox; var password = passwordBox.Password; //Now go ahead and check the user name and password } 

ViewModel görünüşün necə tətbiq edildiyi barədə bir şey bildiyi üçün bu MVVM modelini bir az pozur, amma bu layihədə onu ödəyə bilərəm. İnşallah kimsə bu üçün faydalıdır.

150
10 янв. Konamiman tərəfindən 10 yanvarda verilən cavab 2011-01-10 20:57 '11 at 20:57 2011-01-10 20:57

Bəlkə bir şey buraxmışdım, amma bu həllərin əksəriyyəti işləmək və təhlükəsiz metodları aradan qaldırmaq üçün çətin olur.

Bu üsul MVVM modelini pozmur və tam təhlükəsizlik təmin edir. Bəli, texniki olaraq, bu arxasında kod, ancaq "xüsusi vəziyyət" bağlayıcı bir şey deyil. ViewModel ViewBox-ı ViewModel-ə köçürməyə çalışarsanız, Mənim fikrimcə bu, görünüşün həyata keçirilməsindən xəbərdar deyildir.

Kod arxasında! = Avtomatik MVVM pozulması. Bütün bunlar nə ilə əlaqədardır. Bu halda, biz sadəcə əl ilə kodlaşdırma, belə ki, istifadəçi interfeysi tətbiqi və bu səbəbdən görə.

ViewModel yalnız bir mülkdir. Mən bunu "yalnız yazdım", çünki nədənsə onu ViewModel kənarından almaq lazım deyil, amma bu lazım deyil. Bu yalnız bir simli deyil, bir SecureString olduğunu unutmayın.

 public SecureString SecurePassword { private get; set; } 

Xaml'da, PasswordChanged hadisə işleyicisini konfiqurasiya etdiniz.

 <PasswordBox PasswordChanged="PasswordBox_PasswordChanged"/> 

Arxada olan kodda:

 private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e) { if (this.DataContext != null) { ((dynamic)this.DataContext).SecurePassword = ((PasswordBox)sender).SecurePassword; } } 

Bu üsulla, parol həmişə SecureStringdə qalır və bu səbəbdən maksimum təhlükəsizlik təmin edir. Əgər həqiqətən təhlükəsizlik haqqında düşünməsə və ya onu tələb edən sonrakı metod üçün təmiz bir mətn paroluna ehtiyacınız varsa (Qeyd: bir parol tələb edən ən .NET metodları da SecureString parametrini dəstəkləyir, belə ki, hətta əgər aydın mətn paroluna ehtiyacınız olmaya bilər bu halda ola bilər), sadəcə Parol əmlakını istifadə edə bilərsiniz. Burada:

(əmlak ViewModel)

 public string Password { private get; set; } 

(Arxasında kod)

 private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e) { if (this.DataContext != null) { ((dynamic)this.DataContext).Password = ((PasswordBox)sender).Password; } } 

Hər şeyi ciddi şəkildə yazmaq istəsəniz, ViewModel interfeysi ilə dinamik siyahıdan istifadə edə bilərsiniz. Amma əslində, "normal" məlumat bağlamaları güclü şəkildə yazılmır, belə ki, onların çoxu yoxdur.

 private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e) { if (this.DataContext != null) { ((IMyViewModel)this.DataContext).Password = ((PasswordBox)sender).Password; } } 

Beləliklə, bütün aləmlərin ən yaxşısı - parolunuz qorunur, ViewModel başqa xüsusiyyətlər kimi, sadəcə bir mülkiyyətə malikdir və görünüşünüzün xarici əlaqələri tələb etmir.

116
28 июля '14 в 20:45 2014-07-28 20:45 Cavab 28 iyul 2014-cü il saat 20: 45-də Steve İn CO tərəfindən verilir

XAML istifadə edə bilərsiniz:

 <PasswordBox Name="PasswordBox"> <i:Interaction.Triggers> <i:EventTrigger EventName="PasswordChanged"> <i:InvokeCommandAction Command="{Binding PasswordChangedCommand}" CommandParameter="{Binding ElementName=PasswordBox}"/> </i:EventTrigger> </i:Interaction.Triggers> </PasswordBox> 

Və bu əmr üsulu həyata keçirir:

 private void ExecutePasswordChangedCommand(PasswordBox obj) { if (obj != null) Password = obj.Password; } 
15
03 сент. Cavab verilir Sergey 03 sep. 2014-09-03 12:44 '14 da 12:44 2014-09-03 12:44

Bu mənim üçün gözəl işləyir.

 <Button Command="{Binding Connect}" CommandParameter="{Binding ElementName=MyPasswordBox}"/> 
10
13 окт. Cavab 13 oktyabrda Vladislav Borovikov tərəfindən verilir . 2009-10-13 17:21 '09 at 17:21 'da 2009-10-13 17:21

MVVM modelini pozmayan sadə bir həll, parol toplayan ViewModeldə hadisə (və ya nümayəndə) təmsil etməkdir.

ViewModeldə :

public event EventHandler<HarvestPasswordEventArgs> HarvestPassword;

bu EventArgs ilə:

 class HarvestPasswordEventArgs : EventArgs { public string Password; } 

Görünümdə, ViewModel yaratdığınızda və parol dəyərini daxil edərkən hadisəyə abunə olun.

 _viewModel.HarvestPassword += (sender, args) => args.Password = passwordBox1.Password; 

ViewModel-də bir şifrə ehtiyac duyduğunuzda, bu hadisə başladın və paroldan çıxarın:

 if (HarvestPassword == null) //bah return; var pwargs = new HarvestPasswordEventArgs(); HarvestPassword(this, pwargs); LoginHelpers.Login(Username, pwargs.Password); 
8
17 окт. Cavab Jan Willem B 17 okta verilir. 2012-10-17 12:29 '12 at 12:29 2012-10-17 12:29

Burada yapışqan parol olan bir GIST yazdım .

 using System.Windows; using System.Windows.Controls; namespace CustomControl { public class BindablePasswordBox : Decorator { /// <summary> /// The password dependency property. /// </summary> public static readonly DependencyProperty PasswordProperty; private bool isPreventCallback; private RoutedEventHandler savedCallback; /// <summary> /// Static constructor to initialize the dependency properties. /// </summary> static BindablePasswordBox() { PasswordProperty = DependencyProperty.Register( "Password", typeof(string), typeof(BindablePasswordBox), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnPasswordPropertyChanged)) ); } /// <summary> /// Saves the password changed callback and sets the child element to the password box. /// </summary> public BindablePasswordBox() { savedCallback = HandlePasswordChanged; PasswordBox passwordBox = new PasswordBox(); passwordBox.PasswordChanged += savedCallback; Child = passwordBox; } /// <summary> /// The password dependency property. /// </summary> public string Password { get { return GetValue(PasswordProperty) as string; } set { SetValue(PasswordProperty, value); } } /// <summary> /// Handles changes to the password dependency property. /// </summary> /// <param name="d">the dependency object</param> /// <param name="eventArgs">the event args</param> private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs eventArgs) { BindablePasswordBox bindablePasswordBox = (BindablePasswordBox) d; PasswordBox passwordBox = (PasswordBox) bindablePasswordBox.Child; if (bindablePasswordBox.isPreventCallback) { return; } passwordBox.PasswordChanged -= bindablePasswordBox.savedCallback; passwordBox.Password = (eventArgs.NewValue != null) ? eventArgs.NewValue.ToString() : ""; passwordBox.PasswordChanged += bindablePasswordBox.savedCallback; } /// <summary> /// Handles the password changed event. /// </summary> /// <param name="sender">the sender</param> /// <param name="eventArgs">the event args</param> private void HandlePasswordChanged(object sender, RoutedEventArgs eventArgs) { PasswordBox passwordBox = (PasswordBox) sender; isPreventCallback = true; Password = passwordBox.Password; isPreventCallback = false; } } } 
8
09 июля '10 в 19:17 2010-07-09 19:17 Cavab Taylor Leese tərəfindən 09.07.10 19:17 tarixində verilib 2010-07-09 19:17

MVVM pozulmadan OP problemini həll etmək üçün parol pəncərəsindən alınan dəyər (parol) üçün xüsusi bir dəyər çeviricisini və bir sarmalayıcıdan istifadə edəcəyəm.

 public interface IWrappedParameter<T> { T Value { get; } } public class PasswordBoxWrapper : IWrappedParameter<string> { private readonly PasswordBox _source; public string Value { get { return _source != null ? _source.Password : string.Empty; } } public PasswordBoxWrapper(PasswordBox source) { _source = source; } } public class PasswordBoxConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { // Implement type and value check here... return new PasswordBoxWrapper((PasswordBox)value); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new InvalidOperationException("No conversion."); } } 

Görünüş modelində:

 public string Username { get; set; } public ICommand LoginCommand { get { return new RelayCommand<IWrappedParameter<string>>(password => { Login(Username, password); }); } } private void Login(string username, string password) { // Perform login here... } 

IWrappedParameter<T> modelində IWrappedParameter<T> istifadə IWrappedParameter<T> üçün PasswordBoxWrapperPasswordBoxConverter haqqında hər hansı bir məlumatı bilməməsi lazım deyil. Beləliklə, PasswordBox obyektini təqdimat modeldən təcrid edə və MVVM modelini pozmayın.

Təqdimatda:

 <Window.Resources> <h:PasswordBoxConverter x:Key="PwdConverter" /> </Window.Resources> ... <PasswordBox Name="PwdBox" /> <Button Content="Login" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=PwdBox, Converter={StaticResource PwdConverter}}" /> 
6
12 марта '14 в 17:56 2014-03-12 17:56 Cavab Aoi Karasu tərəfindən 12 mart 2014-cü il saat 17: 14-də verilir

Bu tətbiq bir az fərqlidir. ViewModel-də əmlakın bağlanması yolu ilə parol keçirmək, hər hansı bir komanda parametrini istifadə etmir. ViewModel görünüşündə hələ də məlum deyil. SkyDrive-dan yüklənə biləcək VB-2010 layihəsi var. Wpf MvvM PassWordBox Örnek.zip https://skydrive.live.com/redir.aspx?cid=e95997d33a9f8d73>

Bir Wpf MvvM proqramında PasswordBox istifadə etmə üsulu olduqca sadədir və mənim üçün yaxşı işləyir. Bu məncə, bu, doğru yol və ya ən yaxşı yoldur. Bu, PasswordBox və MvvM şablonunun istifadəsinin bir tətbiqidir.

Əsasən, View bir PasswordBox (faktiki nəzarət) kimi bağlaya biləcək bir oxuya bilən ümumi mülk yaratırsınız. Misal:

 Private _thePassWordBox As PasswordBox Public ReadOnly Property ThePassWordBox As PasswordBox Get If IsNothing(_thePassWordBox) Then _thePassWordBox = New PasswordBox Return _thePassWordBox End Get End Property 

Mən dəstək alanını yalnız öz-özünə başlamaq xüsusiyyətlərindən istifadə edirəm.

Sonra Xaml-dan ContentControl və ya idarə konteynerinin məzmununu bağlayırsınız. Məsələn:

  <ContentControl Grid.Column="1" Grid.Row="1" Height="23" Width="120" Content="{Binding Path=ThePassWordBox}" HorizontalAlignment="Center" VerticalAlignment="Center" /> 

Buradan parol üzərində tam nəzarətə sahibsiniz. Parola dəyərini girişdə və ya parol istifadə etmək istədiyiniz başqa bir yerə qaytarmaq üçün PasswordAccessor (Yalnız bir String funksiyası) istifadə edirəm. Məsələn, ümumi bir istifadəçi obyekti modelində ictimaiyyətə çatdırılma imkanı var. Məsələn:

 Public Property PasswordAccessor() As Func(Of String) 

Istifadəçi obyektində parol simli mülkiyyəti hər hansı bir backup storage olmadan oxuyur, sadəcə PasswordBox-dan parol qaytarır. Məsələn:

 Public ReadOnly Property PassWord As String Get Return If((PasswordAccessor Is Nothing), String.Empty, PasswordAccessor.Invoke()) End Get End Property 

Sonra ViewModeldə Accessorun PasswordBox.Password xüsusiyyətində yaradıldığını və təyin olunduğunu əmin edirəm. Məsələn:

 Public Sub New() 'Sets the Accessor for the Password Property SetPasswordAccessor(Function() ThePassWordBox.Password) End Sub Friend Sub SetPasswordAccessor(ByVal accessor As Func(Of String)) If Not IsNothing(VMUser) Then VMUser.PasswordAccessor = accessor End Sub 

Daxil olmaq üçün bir parol dize ehtiyacım olduqda, mən, sadəcə, parolun ələ alınması və geri qaytarılması üçün funksiyanı çağırır və istifadəçi obyektində əsl parol saxlanmayan İstifadəçi Nesneleri Şifrəsini əldə edirəm. Məsələn: ViewModel olacaq

 Private Function LogIn() as Boolean 'Make call to your Authentication methods and or functions. I usally place that code in the Model Return AuthenticationManager.Login(New UserIdentity(User.UserName, User.Password) End Function 

Bunu etmək lazımdır. ViewModel View idarəetmə məlumatlarına ehtiyac duymur. View Yalnız obyekt ObjectModel-də bir obyektə bağlıdır, lakin bir görüntüyə və ya digər resursa cəlb görünüşündən başqa. Bu halda, bu resurs (Əmlak) sadəcə usercontroldır. ViewModel Əmlak yaradıb və sahibi olduğu üçün obyektin görünüşündən asılı olaraq test etməyə imkan verir. Təhlükəsizliyə gəlincə, bu tətbiqin nə qədər yaxşı olduğunu bilmirəm. Amma funksiyanı istifadə edərək, əmlak yalnız əmlak vasitəsilə əldə olunan əmlakın özündə saxlanılır.

31 авг. William Rawson tərəfindən verilmiş cavab 31 avqust 2011-08-31 09:36 '11 saat 09:36 'da 2011-08-31 09:36

Şifrəni heç yerdə saxlamamaq vacibdirsə də, təqdimat modeli olmadan bir təqdimat modeli yaratmaq və testlərimi yerinə yetirmək üçün hələ də fürsətə ehtiyac duyuram.

Mənim üçün çalışdığım həll, PasswordBox.Password funksiyasını görünüş modeli ilə qeydiyyatdan keçirmək və giriş kodunu icra edərkən görünüş modelini çağırmaq idi.

Kod kodunda bir kod satırı deməkdir.

Beləliklə, mənim Login.xamldə var

 <PasswordBox x:Name="PasswordBox"/> 

və Login.xaml.cs ilə var

 LoginViewModel.PasswordHandler = () => PasswordBox.Password; 

LoginViewModel.cs bir PasswordHandler müəyyən etdik

 public Func<string> PasswordHandler { get; set; } 

və girişin baş verdiyi zaman, kodu işarəni görünüşdən parol almaq üçün çağırır ...

 bool loginResult = Login(Username, PasswordHandler()); 

Görünüş modeli sınamaqda, PasswordHandler'ı testdə istifadə etmək istəmədiyim hər hansı bir parolun keçməsinə imkan verən anonim bir metoddur.

5
16 окт. mike mckechnie 16 oct tərəfindən verilmiş cavab . 2014-10-16 16:07 '14 'da 16:07 2014-10-16 16:07

Mən müxtəlif həllər üzərində çox vaxt sərf etmişəm. Dekoratorların fikirlərini sevməmişəm, davranış yoxlanmanın istifadəçi interfeyasını pozmuşdu, kodu ... həqiqətən?

Xüsusi əlavə xüsusiyyət ilə qalmaq və görünüş modelinizdə SecureString əmlakına bağlamaq ən SecureString . Mümkün olduğu qədər orada saxlayın. Sadə bir parolaya sürətli girmə imkanı lazım olduqda, müvəqqəti olaraq aşağıdakı kodu istifadə edərək qorunmayan bir dize çeviriniz:

 namespace Namespace.Extensions { using System; using System.Runtime.InteropServices; using System.Security; /// <summary> /// Provides unsafe temporary operations on secured strings. /// </summary> [SuppressUnmanagedCodeSecurity] public static class SecureStringExtensions { /// <summary> /// Converts a secured string to an unsecured string. /// </summary> public static string ToUnsecuredString(this SecureString secureString) { // copy from the internal System.Net.UnsafeNclNativeMethods IntPtr bstrPtr = IntPtr.Zero; if (secureString != null) { if (secureString.Length != 0) { try { bstrPtr = Marshal.SecureStringToBSTR(secureString); return Marshal.PtrToStringBSTR(bstrPtr); } finally { if (bstrPtr != IntPtr.Zero) Marshal.ZeroFreeBSTR(bstrPtr); } } } return string.Empty; } /// <summary> /// Copies the existing instance of a secure string into the destination, clearing the destination beforehand. /// </summary> public static void CopyInto(this SecureString source, SecureString destination) { destination.Clear(); foreach (var chr in source.ToUnsecuredString()) { destination.AppendChar(chr); } } /// <summary> /// Converts an unsecured string to a secured string. /// </summary> public static SecureString ToSecuredString(this string plainString) { if (string.IsNullOrEmpty(plainString)) { return new SecureString(); } SecureString secure = new SecureString(); foreach (char c in plainString) { secure.AppendChar(c); } return secure; } } } 

GC-nin istifadəçi interfeysi elementini toplamasına icazə verdiyinizdən əmin olun, belə ki PasswordChanged hadisə üçün statik bir hadisə işleyicisini istifadə etməyə diqqət yetirməyin. SecurePassword konfiqurasiya etmək üçün istifadə edərkən istifadəçi interfeysi yeniləmədikdə anomaliya aşkar etdim, bunun əvəzinə şifrəni SecurePassword kopyalayıram.

 namespace Namespace.Controls { using System.Security; using System.Windows; using System.Windows.Controls; using Namespace.Extensions; /// <summary> /// Creates a bindable attached property for the <see cref="PasswordBox.SecurePassword"/> property. /// </summary> public static class PasswordBoxHelper { // an attached behavior won't work due to view model validation not picking up the right control to adorn public static readonly DependencyProperty SecurePasswordBindingProperty = DependencyProperty.RegisterAttached( "SecurePassword", typeof(SecureString), typeof(PasswordBoxHelper), new FrameworkPropertyMetadata(new SecureString(),FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, AttachedPropertyValueChanged) ); private static readonly DependencyProperty _passwordBindingMarshallerProperty = DependencyProperty.RegisterAttached( "PasswordBindingMarshaller", typeof(PasswordBindingMarshaller), typeof(PasswordBoxHelper), new PropertyMetadata() ); public static void SetSecurePassword(PasswordBox element, SecureString secureString) { element.SetValue(SecurePasswordBindingProperty, secureString); } public static SecureString GetSecurePassword(PasswordBox element) { return element.GetValue(SecurePasswordBindingProperty) as SecureString; } private static void AttachedPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // we'll need to hook up to one of the element events // in order to allow the GC to collect the control, we'll wrap the event handler inside an object living in an attached property // don't be tempted to use the Unloaded event as that will be fired even when the control is still alive and well (eg switching tabs in a tab control) var passwordBox = (PasswordBox)d; var bindingMarshaller = passwordBox.GetValue(_passwordBindingMarshallerProperty) as PasswordBindingMarshaller; if (bindingMarshaller == null) { bindingMarshaller = new PasswordBindingMarshaller(passwordBox); passwordBox.SetValue(_passwordBindingMarshallerProperty, bindingMarshaller); } bindingMarshaller.UpdatePasswordBox(e.NewValue as SecureString); } /// <summary> /// Encapsulated event logic /// </summary> private class PasswordBindingMarshaller { private readonly PasswordBox _passwordBox; private bool _isMarshalling; public PasswordBindingMarshaller(PasswordBox passwordBox) { _passwordBox = passwordBox; _passwordBox.PasswordChanged += this.PasswordBoxPasswordChanged; } public void UpdatePasswordBox(SecureString newPassword) { if (_isMarshalling) { return; } _isMarshalling = true; try { // setting up the SecuredPassword won't trigger a visual update so we'll have to use the Password property _passwordBox.Password = newPassword.ToUnsecuredString(); // you may try the statement below, however the benefits are minimal security wise (you still have to extract the unsecured password for copying) //newPassword.CopyInto(_passwordBox.SecurePassword); } finally { _isMarshalling = false; } } private void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e) { // copy the password into the attached property if (_isMarshalling) { return; } _isMarshalling = true; try { SetSecurePassword(_passwordBox, _passwordBox.SecurePassword.Copy()); } finally { _isMarshalling = false; } } } } } 

XAML istifadə:

 <PasswordBox controls:PasswordBoxHelper.SecurePassword="{Binding LogonPassword, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"> 

Görünüş modelindəki əmlakım buna bənzərdi:

 [RequiredSecureString] public SecureString LogonPassword { get { return _logonPassword; } set { _logonPassword = value; NotifyPropertyChanged(nameof(LogonPassword)); } } 

RequiredSecureString aşağıdakı məntiqə malik sadə bir istifadəçi qiymətləndiricidir:

 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] public class RequiredSecureStringAttribute:ValidationAttribute { public RequiredSecureStringAttribute() :base("Field is required") { } public override bool IsValid(object value) { return (value as SecureString)?.Length > 0; } } 

Burada var. Tamamlanmış və sübut olunmuş təmiz MVVM həlli.

3
18 февр. MoonStom Fev 18 2016-02-18 09:00 '16 saat 9:00 'da 2016-02-18 09:00' də

MVVM pozur baxmayaraq, mən bu metoddan istifadə etmişəm və parol sahəsində keçdim, çünki mənim üçün əhəmiyyətli idi, çünki kompleks bir qoruma mühiti olan mənim qabığımı daxil etmək üçün məlumat şablonu ilə kontent nəzarətindən istifadə etdim. Beləliklə, kabukun arxasındakı kodu girmədi.

Şifrəni köçürərkən, mən bildiyim kimi, arxiv kodundan idarəolunma ilə eyni olduğunu düşünürəm. Şifrələrlə razıyam, yaddaşda saxlamıram və s. Bu tətbiqdə, görünüş modelində şifrə malik deyiləm.

Button əmri

 Command="{Binding Path=DataContext.LoginCommand, ElementName=MyShell}" CommandParameter="{Binding ElementName=PasswordBox}" 

Viewmodel

 private void Login(object parameter) { System.Windows.Controls.PasswordBox p = (System.Windows.Controls.PasswordBox)parameter; MessageBox.Show(p.Password); } 
3
30 июля '11 в 8:30 2011-07-30 08:30 Cavab Legz tərəfindən 30 İyul 2011 tarixində saat 8.30 'də verildi. 2011-07-30 08:30

Çox sadədir. Создайте другое свойство для пароля и привяжите его к TextBox

Но все операции ввода выполняются с фактическим свойством пароля

частная строка _Password;

  public string PasswordChar { get { string szChar = ""; foreach(char szCahr in _Password) { szChar = szChar + "*"; } return szChar; } set { _PasswordChar = value; NotifyPropertyChanged(); } } 

публичная строка Пароль { получить { return _Password; }

  set { _Password = value; NotifyPropertyChanged(); PasswordChar = _Password; } } 

2
ответ дан Niji 26 сент. '16 в 16:01 2016-09-26 16:01

В универсальном приложении Windows

вы можете использовать этот код со свойством "Пароль" и привязкой к modelView

2
ответ дан Baz08 12 апр. '16 в 12:09 2016-04-12 12:09

Я решил, что брошу свое решение в микс, так как это такая распространенная проблема... и наличие большого количества опций всегда хорошо.

Я просто обернул PasswordBox в UserControl и реализовал a DependencyProperty , чтобы иметь возможность связывать. Я делаю все, что в моих силах, чтобы не хранить ясный текст в памяти, поэтому все делается с помощью свойств SecureString и PasswordBox.Password . Во время цикла foreach каждый символ становится открытым, но он очень короткий. Честно говоря, если вы беспокоитесь о том, что ваше приложение WPF будет скомпрометировано из этой краткой экспозиции, у вас появятся более серьезные проблемы с безопасностью, которые должны быть обработаны.

Красота заключается в том, что вы не нарушаете никаких правил MVVM, даже "пуристских", так как это UserControl , поэтому это позволяет иметь код. Когда вы его используете, вы можете иметь чистую связь между View и ViewModel , не сообщив VideModel о какой-либо части View или источнике пароля. Просто убедитесь, что вы привязываетесь к SecureString в своем ViewModel .

BindablePasswordBox.xaml

 <UserControl x:Class="BK.WPF.CustomControls.BindanblePasswordBox" 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="22" d:DesignWidth="150"> <PasswordBox x:Name="PswdBox"/> </UserControl> 

BindablePasswordBox.xaml.cs(версия 1 - поддержка двусторонней привязки.)

 using System.ComponentModel; using System.Security; using System.Windows; using System.Windows.Controls; namespace BK.WPF.CustomControls { public partial class BindanblePasswordBox : UserControl { public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(SecureString), typeof(BindanblePasswordBox)); public SecureString Password { get { return (SecureString)GetValue(PasswordProperty); } set { SetValue(PasswordProperty, value); } } public BindanblePasswordBox() { InitializeComponent(); PswdBox.PasswordChanged += PswdBox_PasswordChanged; } private void PswdBox_PasswordChanged(object sender, RoutedEventArgs e) { var secure = new SecureString(); foreach (var c in PswdBox.Password) { secure.AppendChar(c); } Password = secure; } } } 

Использование версии 1:

 <local:BindanblePasswordBox Width="150" HorizontalAlignment="Center" VerticalAlignment="Center" Password="{Binding Password, Mode=OneWayToSource}"/> 

BindablePasswordBox.xaml.cs(версия 2 - поддерживает двустороннюю привязку.)

 public partial class BindablePasswordBox : UserControl { public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(SecureString), typeof(BindablePasswordBox), new PropertyMetadata(PasswordChanged)); public SecureString Password { get { return (SecureString)GetValue(PasswordProperty); } set { SetValue(PasswordProperty, value); } } public BindablePasswordBox() { InitializeComponent(); PswdBox.PasswordChanged += PswdBox_PasswordChanged; } private void PswdBox_PasswordChanged(object sender, RoutedEventArgs e) { var secure = new SecureString(); foreach (var c in PswdBox.Password) { secure.AppendChar(c); } if (Password != secure) { Password = secure; } } private static void PasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var pswdBox = d as BindablePasswordBox; if (pswdBox != null  e.NewValue != e.OldValue) { var newValue = e.NewValue as SecureString; if (newValue == null) { return; } var unmanagedString = IntPtr.Zero; string newString; try { unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(newValue); newString = Marshal.PtrToStringUni(unmanagedString); } finally { Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString); } var currentValue = pswdBox.PswdBox.Password; if (currentValue != newString) { pswdBox.PswdBox.Password = newString; } } } } 

Использование версии 2:

 <local:BindanblePasswordBox Width="150" HorizontalAlignment="Center" VerticalAlignment="Center" Password="{Binding Password, Mode=TwoWay}"/> 
2
ответ дан BK 22 сент. '15 в 7:47 2015-09-22 07:47

вы можете сделать это с прикрепленным свойством, см. его PasswordBox с MVVM

2
ответ дан Rangel 29 сент. '09 в 17:54 2009-09-29 17:54

Для тех, кто знает о рисках, которые эта реализация накладывает, чтобы синхронизация паролей с вашей ViewModel просто добавила Mode = OneWayToSource .

XAML

 <PasswordBox ff:PasswordHelper.Attach="True" ff:PasswordHelper.Password="{Binding Path=Password, Mode=OneWayToSource}" /> 
2
ответ дан Kevin 13 нояб. '13 в 13:32 2013-11-13 13:32

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

Это прикрепленное свойство . Этот тип свойства может быть применен к любому типу DependencyObject , а не только к типу, в котором он объявлен. Поэтому, хотя он объявлен в статическом классе PasswordHelper , он применяется к PasswordBox , на котором вы его используете.

Чтобы использовать это вложенное свойство, вам просто нужно привязать его к свойству Password в ViewModel:

 <PasswordBox w:PasswordHelper.Attach="True" w:PasswordHelper.Password="{Binding Password}"/> 
1
ответ дан Thomas Levesque 27 сент. '09 в 19:45 2009-09-27 19:45

Как уже упоминалось ранее, VM не должна знать о View, но передача всего PasswordBox выглядит как самый простой подход. Поэтому, возможно, вместо того, чтобы кастовать переданный параметр в PasswordBox, используйте Reflection, чтобы извлечь из него свойство Password. В этом случае VM ожидает какой-то контейнер паролей с свойством Password (я использую RelayCommands из MVMM Light-Toolkit):

 public RelayCommand<object> SignIn { get { if (this.signIn == null) { this.signIn = new RelayCommand<object>((passwordContainer) => { var password = passwordContainer.GetType().GetProperty("Password").GetValue(passwordContainer) as string; this.authenticationService.Authenticate(this.Login, password); }); } return this.signIn; } } 

Он может быть легко протестирован с анонимным классом:

 var passwordContainer = new { Password = "password" }; 
1
ответ дан mokula 03 нояб. '13 в 12:09 2013-11-03 12:09

Вы найдете решение для PasswordBox в приложении примера ViewModel WPF Application Framework (WAF) проект.

Однако Джастин прав. Не передавайте пароль как обычный текст между View и ViewModel. Вместо этого используйте SecureString (см. MSDN PasswordBox).

0
ответ дан jbe 02 окт. '09 в 20:58 2009-10-02 20:58

Я сделал:

XAML:

 <PasswordBox x:Name="NewPassword" PasswordChanged="NewPassword_PasswordChanged"/> <!--change tablenameViewSource: yours!--> <Grid DataContext="{StaticResource tablenameViewSource}" Visibility="Hidden"> <TextBox x:Name="Password" Text="{Binding password, Mode=TwoWay}"/> </Grid> 

#

 private void NewPassword_PasswordChanged(object sender, RoutedEventArgs e) { try { //change tablenameDataTable: yours! and tablenameViewSource: yours! tablenameDataTable.Rows[tablenameViewSource.View.CurrentPosition]["password"] = NewPassword.Password; } catch { this.Password.Text = this.NewPassword.Password; } } 

Mənim üçün işləyir!

0
ответ дан José Roberto Cuello Alcaraz 15 окт. '13 в 23:23 2013-10-15 23:23

Я использовал проверку проверки подлинности, а затем подзвал, вызываемый классом посредника, в представление (который также реализует проверку подлинности), чтобы записать пароль в класс данных.

Это не идеальное решение; однако он устранил мою проблему неспособности переместить пароль.

0
ответ дан Miles 22 мая '14 в 18:12 2014-05-22 18:12

Я потратил годы, пытаясь заставить это работать. В конце концов, я сдался и просто использовал PasswordBoxEdit из DevExpress.

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

Решение на веб-сайте DevExpress

Для записи я никак не связан с DevExpress.

0
ответ дан Contango 28 окт. '14 в 19:10 2014-10-28 19:10

Я использую сжатое MVVM-решение, которое еще не упоминалось. Во-первых, я называю PasswordBox в XAML:

 <PasswordBox x:Name="Password" /> 

Затем я добавляю один вызов метода в конструктор вида:

 public LoginWindow() { InitializeComponent(); ExposeControl<LoginViewModel>.Expose(this, view => view.Password, (model, box) => model.SetPasswordBox(box)); } 

Və nədir. Модель просмотра получит уведомление, когда оно подключено к представлению через DataContext и другое уведомление, когда оно отсоединено. Содержимое этого уведомления настраивается через lambdas, но обычно это просто вызов сеттера или метода в модели представления, передающий проблемное управление в качестве параметра.

Это можно сделать MVVM-friendly очень легко, открыв интерфейс вместо дочерних элементов управления.

Вышеприведенный код основан на вспомогательном классе , опубликованном в моем блоге.

0
ответ дан Robert Važan 16 июля '14 в 20:54 2014-07-16 20:54

Для меня обе эти вещи не так:

  • Реализация свойств текстового пароля
  • Отправка PasswordBox в качестве параметра команды в ViewModel

Перенос SecurePassword (экземпляр SecureString), как описано Steve in CO , кажется приемлемым. Я предпочитаю Behaviors закодировать код, и у меня также было дополнительное требование о возможности reset пароля из режима просмотра.

Xaml ( Password - свойство ViewModel):

 <PasswordBox> <i:Interaction.Behaviors> <behaviors:PasswordBinding BoundPassword="{Binding Password, Mode=TwoWay}" /> </i:Interaction.Behaviors> </PasswordBox> 

Поведение:

 using System.Security; using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity; namespace Evidence.OutlookIntegration.AddinLogic.Behaviors { /// <summary> /// Intermediate class that handles password box binding (which is not possible directly). /// </summary> public class PasswordBoxBindingBehavior : Behavior<PasswordBox> { // BoundPassword public SecureString BoundPassword { get { return (SecureString)GetValue(BoundPasswordProperty); } set { SetValue(BoundPasswordProperty, value); } } public static readonly DependencyProperty BoundPasswordProperty = DependencyProperty.Register("BoundPassword", typeof(SecureString), typeof(PasswordBoxBindingBehavior), new FrameworkPropertyMetadata(OnBoundPasswordChanged)); protected override void OnAttached() { this.AssociatedObject.PasswordChanged += AssociatedObjectOnPasswordChanged; base.OnAttached(); } /// <summary> /// Link up the intermediate SecureString (BoundPassword) to the UI instance /// </summary> private void AssociatedObjectOnPasswordChanged(object s, RoutedEventArgs e) { this.BoundPassword = this.AssociatedObject.SecurePassword; } /// <summary> /// Reacts to password reset on viewmodel (ViewModel.Password = new SecureString()) /// </summary> private static void OnBoundPasswordChanged(object s, DependencyPropertyChangedEventArgs e) { var box = ((PasswordBoxBindingBehavior)s).AssociatedObject; if (box != null) { if (((SecureString)e.NewValue).Length == 0) box.Password = string.Empty; } } } } 
0
ответ дан Mike Fuchs 07 окт. '14 в 20:15 2014-10-07 20:15

хорошо, мой ответ более прост как раз в шаблоне MVVM

в классе viewmodel

 public string password; PasswordChangedCommand = new DelegateCommand<RoutedEventArgs>(PasswordChanged); Private void PasswordChanged(RoutedEventArgs obj) { var e = (WatermarkPasswordBox)obj.OriginalSource; //or depending or what are you using var e = (PasswordBox)obj.OriginalSource; password =e.Password; } 

свойство пароля PasswordBox, которое обеспечивает win или WatermarkPasswordBox, которое предоставляет XCeedtoolkit, генерирует RoutedEventArgs, поэтому вы можете связать его.

теперь в представлении xmal

 <Xceed:WatermarkPasswordBox Watermark="Input your Password" Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="7" PasswordChar="*" > <i:Interaction.Triggers> <i:EventTrigger EventName="PasswordChanged"> <prism:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path= DataContext.PasswordChangedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path= Password}"/> </i:EventTrigger> </i:Interaction.Triggers> </Xceed:WatermarkPasswordBox> 

və ya

 <PasswordBox Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="7" PasswordChar="*" > <i:Interaction.Triggers> <i:EventTrigger EventName="PasswordChanged"> <prism:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path= DataContext.PasswordChangedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path= Password}"/> </i:EventTrigger> </i:Interaction.Triggers> </PasswordBox> 
0
ответ дан carlos rodriguez 31 июля '17 в 21:17 2017-07-31 21:17

Другие вопросы по меткам или Задайте вопрос