在WPF-MVVM中使用密码框

8
我已经阅读了几篇关于如何使用附加属性在WPF中绑定PasswordBox值的文章。然而,每篇文章都引用了.NET文档,解释了为什么PasswordBox一开始就没有被设计成可绑定的。
我并不认为自己是安全专家,但我想微软的某个人知道他们在做什么,我不应该花费精力试图撤销它。
因此,我想出了自己的解决方案。
public class LoginViewModel
{
   // other properties here

   public PasswordBox Password
   {
      get { return m_passwordBox; }
   }

   // Executed when the Login button is clicked.
   private void LoginExecute()
   {
      var password = Password.SecurePassword;

      // do more stuff...
   }
}

然后,在我的XAML中,我只需将Password字段绑定到ContentPresenter,就可以渲染出PasswordBox。那么我的问题是...这样做有问题吗?我意识到我在某种程度上打破了MVVM的规则,因为我让实际控件出现在我的ViewModel中,但至少这似乎比仅仅取消密码字段的保护更正确。如果这实际上是一个问题,是否有人想出了一种解决方案,而不涉及使用附加属性并将密码存储在ViewModel中?谢谢!-J

1
附加属性方法的问题到底是什么?是属性类型为字符串吗?为什么不改成SecureString呢? - Kent Boogaart
就像我之前所说,似乎有一个原因它一开始不是 DependencyProperty,所以找到一个变通方法似乎是错误的。我想我同样可以绑定到 SecurePassword 属性。 - jeremyalan
1
当 Password 属性是可绑定的时,问题在于:它的值很容易被外部软件跟踪,比如 SNOOP。这样你的密码就很容易被盗取了。 - ktutnik
能否解释一下ContentPresenter是什么? - Juan Zamudio
@ktutnik 我知道这是一个很老的问题,但只要我能输入密码,启动窃听器,聚焦密码框,检查密码属性并看到明文结果,我就不会太关注这个问题 - 与使用DP相比,拥有属性的增加安全性对我来说并不值得麻烦。 - grek40
4个回答

6

在登录期间至少将密码存储在VM中有什么问题吗?您是正确的,根据MVVM模式,VM不应该引用像PasswordBox这样的控件。

在视图中,添加一个处理程序来处理PasswordChanged事件。在处理程序中,使用passwordbox的SecurePassword更新VM中的SecureString属性。


如上所述,我不是安全专家,我只是尽力遵循文档中规定的指南。但是,与保留对字符串的内存引用相比,保留对SecureString的内存引用是否存在任何风险?如果这不是问题,那么直接绑定它应该是框架的一部分。 - jeremyalan
PasswordBox的Password属性为什么不是依赖属性可以在这里由微软的某个人解释:http://social.msdn.microsoft.com/forums/en-US/wpf/thread/7ca97b60-2d8e-4a27-8c5b-b8d5d7370a5e/。我猜测新的SecurePassword属性也不是依赖属性,因为他们担心如果有人数据绑定到它并在登录后忘记清除它,它就会被锚定在内存中。但这只是一个猜测。 - Wallstreet Programmer
谢谢您的回复。是否有一种方法在登录后“清除它”,以便我可以确保该值不会在登录页面消失后留存在内存中? - jeremyalan
好的,嗯...我刚刚开始 tinkering API,并意识到 SecureString 上有一个 Clear 方法。我认为这就是我要找的东西?TIA -J - jeremyalan
我的解决方案最终成为了一个大杂烩,但这个想法是让我开始的。本质上,我创建了一个附加属性,它允许我绑定到SecurePassword属性。感谢您的输入! - jeremyalan

2

这只是我的建议,希望能对你有所帮助。

  1. 我认为不将密码作为DP的想法是因为它很容易被外部软件(如SNOOP)跟踪。
  2. 你的View Model依赖越少,你的代码就越好。这会在单元测试、升级或更改时对你有所帮助(如果将来你想使用第三方密码框,你会怎么做?)
  3. 抛弃“Code Behind is Useless”状态,明智地使用它。

在你的Code Behind中考虑以下内容:

void loginButton_Clicked(object s, EventArgs e)
{
    myViewModel.Password = txPwdBox.Password;
    myViewModel.Login();
}

我忘了...你应该使用视图优先的方法来完成这个。 - ktutnik

0

我的建议:

在视图模型中加密密码,使用附加属性,并使用ValueConverter来加密/解密密码。这样即使有人使用Snoop,他们只能看到加密的数据。

请告诉我们哪种方法最适合您的情况。


0

我喜欢你的想法。

是的,你在这里违反了ViewModel最佳实践,但是

  • 最佳实践是“在大多数情况下运作良好的建议”,而不是严格的规则;
  • 编写简单易读、可维护的代码并避免不必要的复杂性也是其中的“最佳实践”规则之一(这可能会稍微违反“附加属性”解决方案)。

是否打破View/ViewModel屏障对你是否有问题取决于你首先使用ViewModel的原因(例如,关注点分离、单元测试、可重用性),所以我无法回答。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接