PasswordBox PasswordHelper 多重绑定



在 WPF 中,PasswordBoxPassword属性不是DependencyProperty所以我不能直接绑定到它。作为一种解决方法,我正在使用 https://www.wpftutorial.net/PasswordBox.html 中的此PasswordHelper,它将PasswordHelper.Password附加到PasswordBox,以便我可以绑定到它。

为了防止密码以纯文本形式保留在DataContext中,我想使用一个转换器,该转换器在将密码保存到DataContext之前生成密码的加盐哈希。由于我需要将盐和盐哈希都保存到DataContext,因此我正在使用MultiBindingIMultiValueConverter转换器StringToSaltedHashConverter

我的问题是,当我填写PasswordBox时,我的DataContextPasswordPasswordSalt属性没有得到更新。我已经与Snoop进行了检查,PasswordBoxPasswordPasswordHelper.Password属性都根据我键入的内容而变化。此外,我的StringToSaltedHashConverter也被调用,我返回正确的值。

我在这个表格上还有一些其他绑定(用户名,名字,姓氏,性别......(,它们都工作正常。这是唯一未更新的

¿为什么我的DataContext没有更新?

XAML:

<PasswordBox x:Name="Password"
Style="{DynamicResource PasswordBoxStyle1}"
local:PasswordHelper.Attach="True">
<local:PasswordHelper.Password>
<MultiBinding Converter="{StaticResource StringToSaltedHashConverter}"
Mode="OneWayToSource">
<Binding Path="Password" />
<Binding Path="PasswordSalt" />
</MultiBinding>
</local:PasswordHelper.Password>
</PasswordBox>

代码隐藏:

public class StringToSaltedHashConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
string str = value as string;
string salt = Hash.CreateSalt();
string hash = Hash.CreateHash(str, salt);
object[] vs = { hash, salt };
return vs;
}
}

这不是要走的路。PasswordHelper类和他们的喜欢应该被禁止在互联网上。PasswordBox.Password属性不可绑定,这是有据可查的。访问此属性将创建一个纯文本string表示形式,可以使用免费工具(例如Microsoft进程资源管理器(轻松检索。

获取 Password 属性值时,将密码公开为内存中的纯文本。若要避免此潜在的安全风险,请使用 SecurePassword 属性将密码作为安全字符串获取。

将此属性设置为 null 会导致基础密码设置为"空"。

您甚至将普通盐值存储在内存中 - 我真的希望这既不是商业应用程序也不是公共应用程序。您绝对无法控制垃圾回收器何时从内存中删除任何值。由于String是不可变的类型,因此用户密码的多个副本很可能会在内存中保持公共状态。

在 Windows 环境中,建议的身份验证是使用 Windows 用户身份验证 API。

您至少应该清除PasswordBox.Password属性,方法是将其设置为null

不应在视图中执行加密。

请编写负责任的代码!用户数据不是您的数据

MainWindow.xaml

<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<PasswordBox x:Name="PasswordBox" />
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.PasswordBox.PasswordChanged += OnPasswordChanged;
}
private void OnPasswordChanged(object sender, RoutedEventArgs e)
{
(this.DataContext as ViewModel).Password = this.PasswordBox.SecurePassword;
}
}

视图模型.cs

pucblic class ViewModel
{
private Model Model { get; }
private SecureString password;
public SecureString Password
{
private get => this.password;
public set
{
this.password = value;
OnPasswordChanged();
}
}
private void OnPasswordChanged()
{
// Hash password in the model e.g. to compare it to a hashed database value
this.Model.TryLogin(this.Password);
}
}

型号.cs

public class Model
{
public bool TryLogin(SecureString password)
{  
IntPtr unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(password);
string hashedPassword = HashPassword(Marshal.PtrToStringUni(unmanagedString));
return PasswordIsValid(hashedPassword);
}
private string HashPassword(string unsecurePassword)
{
// Hash algorithm
}
}

在我需要PasswordBox的密码之前,用户会告诉我他已经通过按下按钮完成了输入。

对我来说最好的选择是将ButtonCommandParameterLoginCommand一起使用:

<StackPanel
Width="300"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Label Content="Username:" />
<TextBox Text="{Binding Username}" />
<Label Content="Password:" />
<PasswordBox PasswordChanged="PasswordChanged" />
<StackPanel
Orientation="Horizontal">
<Button
Name="LoginButton"
Command="{Binding LoginCommand}"
Content="Login" />
</StackPanel>
</StackPanel>

查看代码

private void PasswordChanged( object sender, RoutedEventArgs e )
{
LoginButton.CommandParameter = ( sender as PasswordBox ).SecurePassword;
}

视图模型命令

Login = ReactiveCommand.CreateFromTask( async ( SecureString password, CancellationToken cancellationToken ) =>
{
var loggedIn = await AuthenticationService.LoginAsync( Username, password, cancellationToken );
...
} );

我只想感谢大家的回答和令人叹息的评论。你让我意识到我不应该使用PasswordHelper,我根本不应该尝试绑定密码。

以防万一有人遇到类似的问题MultiBinding未正确更新DataContext,这可以通过将OneWayToSource模式添加到MultiBinding中的每个绑定来修复。

<MultiBinding Converter="{StaticResource StringToSaltedHashConverter}" 
Mode="OneWayToSource">
<Binding Path="Password"
Mode="OneWayToSource" />
<Binding Path="PasswordSalt"
Mode="OneWayToSource" />
</MultiBinding>

相关内容

  • 没有找到相关文章

最新更新