【问题标题】:PasswordBox and MVVMPasswordBox 和 MVVM
【发布时间】:2013-03-01 16:58:36
【问题描述】:

我们有以下场景:

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

我已经读过这个Question on PasswordBox in MVVM

但是没有关于如何做的答案!只是“永远不要那样做”。

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

BindingPasswordBox 和 密码不能存储在某个地方,好吗。

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

即使模式被打破了,有没有好的方法来实现这样的事情?

想到了一个Func<string> 来检索它,但没有绑定这个 会弄得一团糟……

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

【问题讨论】:

    标签: c# wpf security mvvm passwordbox


    【解决方案1】:

    我个人只是将整个 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交给服务器吗?
    • @MareInfinitus 我个人会在客户端加密PasswordBox.Password,并将用户名和加密密码传递给服务器,而不是将未加密的 PasswordBox 对象传递给服务器。 PasswordBox.Password 是纯文本,所以我不喜欢将 PasswordBox 对象保留的时间超过我必须的时间。
    • 听起来不错,将仔细研究一下。目前我有一个你建议的命令绑定
    • @MareInfinitus 我见过的系统允许你“记住密码”,这样你就不必每次都输入密码了,它们都将加密的密码存储在机器本地的某个地方,比如就像在注册表中一样,将加密值与用户表中的加密密码进行比较
    • 只是希望有人能真正解决这个问题,但你的解决方案是一条路!谢谢!
    【解决方案2】:

    我通过创建一个公开可以绑定的 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。当然你不应该存储纯文本字符串...

    【讨论】:

    • 这可能是最好的解决方案,但由于代码示例不完整,它是无用的......
    • 您好 Aistis,您能否解释一下您认为样本不完整的原因?我以为我已经提供了足够的信息来解决问题并实施解决方案,但是如果您告诉我缺少的地方,我很乐意更新原始帖子。
    • 嘿@DinoM UserCredentialsInputControl 是什么意思?我正在丢失类型引用..也许是因为我在.net核心中使用它。你能确保吗?
    【解决方案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;
        }
    

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

    【讨论】:

    • 所以您现在在PasswordBoxEdit 中有一个纯文本密码,在您的TextBlock 中有一个加密密码。这如何让事情变得更安全?
    • 它不会也不会让你的想法变得更糟,你可以绑定到它,你不需要交出你的PasswordBox,它比 Rachel 的版本更 MVVM,但这一切仍然取决于您,两种解决方案都可以正常工作并且都是安全的
    • 是的,对不起。我是 WPF 新手,我不知道 Password 不会绑定,因为它不是依赖属性。
    【解决方案4】:

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

    1. 我相信这个问题与PasswordBox Binding 重复
    2. 以上帖子指向-http://www.wpftutorial.net/PasswordBox.html

    【讨论】:

    • 感谢您的回答。但我真的很想要安全!
    【解决方案5】:

    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 存储库中提供了视频源代码的链接。

    【讨论】:

      猜你喜欢
      • 2014-02-09
      • 1970-01-01
      • 2015-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多