PasswordBox和MVVM

问题描述 投票:16回答:4

我们有以下场景:

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

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

但是如何做却没有答案!只是“永远不会那样”。

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

Binding没有正确的PasswordBox方式,密码不能存储在某处,好吧。

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

即使模式被破坏,有没有一种很好的方法来实现这样的事情?

想到一个Func<string>来检索它,但没有Binding这会弄得一团糟......

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

c# wpf security mvvm passwordbox
4个回答
36
投票

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

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

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


4
投票

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


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;
    }

就像你可以看到你的密码是保存的,你可以很容易地绑定它


0
投票

抛弃该文章 - 还有一些与此特定问题相关的其他帖子。您可以使用附加属性实现绑定。请参阅:

  1. 我相信这个问题是PasswordBox Binding的重复
  2. 以上帖子指向 - http://www.wpftutorial.net/PasswordBox.html
© www.soinside.com 2019 - 2024. All rights reserved.