19

我们有以下场景:

  1. 用户可以在其中放置密码的 MVVM 用户界面(实际上是一个PasswordBox
  2. 应该做一些工作的服务器
  3. 服务器连接到一些需要认证的数据库

我已经在 MVVM 中的 PasswordBox 上阅读了这个问题

但是怎么做没有答案!只是“永远不要那样做”。

传递密码的正确方法是什么?如何解决安全问题?

没有正确的方法,Binding并且PasswordBox密码不应存储在某个地方,好吧。

那么,做这些事情的 MVVM 方式是什么?

即使模式被打破,有没有什么好的方法可以实现这样的事情?

想过Func<string>要找回它,但是如果没有 Binding 这会变得一团糟......

从(希望加密的)密码存储中初始化 PasswordBox 的更新 相同。这不是打破 MVVM 模式吗?用户不想在每次启动应用程序或想使用我相信的数据库时输入密码。

4

5 回答 5

39

就我个人而言,我只是将整个PasswordBox控件传递给我的 LoginCommand

我知道它破坏了 MVVM,因为 ViewModel 层现在引用了一个特定于视图的对象,但我认为在这种特定情况下它是可以的。

所以我可能有如下所示的 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 存在的时间不会超过用户登录所需的时间,而实际的“密码”只是文本由用户输入,可能正确也可能不正确。键盘记录器可以为您提供相同的信息。)

于 2013-03-13T16:41:40.630 回答
7

我通过创建一个公开可以绑定的 SecureString 依赖属性的 UserControl 解决了这个问题。此方法始终将密码保存在 SecureString 中,并且不会“破坏” MVVM。

用户控制

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 上的密码属性即可。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。当然你不应该存储纯文本字符串......

于 2015-11-23T23:32:53.900 回答
1

取决于您对 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;
    }

就像您可以看到您的密码已保存并且您可以轻松绑定到它

于 2013-03-20T10:03:10.153 回答
0

把那篇文章放在一边——还有一些与这个特定问题相关的其他帖子。您可以使用附加属性实现绑定。请参见:

  1. 我相信这个问题与 PasswordBox Binding重复
  2. 上面的帖子指向 - http://www.wpftutorial.net/PasswordBox.html
于 2013-03-13T16:25:55.643 回答
0

IMO 上面 DinoM 提出的解决方案是更优雅的解决方案,比上面 Chandramouleswaran Ravichandra 提供的两个链接中使用的“Passwordhelper”类更容易理解(但所有归功于 Samuel Jack 在他的博客http:/ /blog.functionalfun.net/2008/06/wpf-passwordbox-and-data-binding.html )

对于那些因为缺少 'UserCredentialsInputControl' 类型而无法使用 DinoM 解决方案的人,只需将此参数更改为 typeof(PasswordUserControl) 即可。

SingletonSean 在他的 Youtube 频道上有一段视频,标题为;

绑定到 PasswordBox (MVVM) - EASY WPF (.NET CORE) ( https://www.youtube.com/watch?v=G9niOcc5ssw )

这是我找到的作为完整示例的最佳来源,除了他使用字符串而不是 SecureString 作为 PasswordProperty 的基本类型,但这很容易修复。他还在他的 GitHub 存储库中提供了视频源代码的链接。

于 2021-01-23T14:40:31.200 回答