C# 密码框和 MVVM

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15390727/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 16:38:07  来源:igfitidea点击:

PasswordBox and MVVM

c#wpfsecuritymvvmpasswordbox

提问by Mare Infinitus

We have the following scenario:

我们有以下场景:

  1. MVVM userinterface where a user can place his password (actually a PasswordBox)
  2. Server that shall do some work
  3. Server connects to some Database that requires authentification
  1. MVVM 用户界面,用户可以在其中放置密码(实际上是一个PasswordBox
  2. 应该做一些工作的服务器
  3. 服务器连接到一些需要身份验证的数据库

And I already read this Question on PasswordBox in MVVM

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

But there is no answer on how to do! Just lots over "never ever do that".

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

What is the correct way of passing a password around? How to resolve the security issues?

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

There is no proper way of Bindingto the PasswordBoxand the Password shall not be stored somewhere, okay.

有没有适当的方式BindingPasswordBox和密码不得保存在某个地方,好不好。

So, what is the MVVM way of doing such things?

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

Even if the pattern is broken, is there a good way to achieve such things?

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

Thought of a Func<string>to retrieve it, but without Binding this will get a mess...

Func<string>找回它,但没有绑定这会变得一团糟......

UpdateSame for initialising the PasswordBox from a (hopefully encrypted) password store. Isn't that breaking the MVVM pattern? The User does not want to enter the password each time he starts the application or wants to work with the database I believe.

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

采纳答案by Rachel

Personally I just pass the entire PasswordBoxcontrol to my LoginCommand

我个人只是将整个PasswordBox控制权传递给我的 LoginCommand

I know it breaks MVVM because the ViewModel layer now references a View-specific object, but I think in this specific case it's OK.

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

So I might have XAML that looks like this:

所以我可能有如下所示的 XAML:

<Button Content="Login" 
        Command="{Binding LoginCommand}" 
        CommandParameter="{Binding ElementName=MyPasswordBox}" />

And a LoginCommandthat does something like this:

和 aLoginCommand做这样的事情:

private void Login(object obj)
{
    PasswordBox pwBox = obj as PasswordBox;

    SomeBlackBoxClass.ValidatePassword(UserName, pwBox.Password);
}

I suppose you could also run some kind of encryption algorithm on the value and compare the hash of that value to the hash of the user's password too

我想您还可以对该值运行某种加密算法,并将该值的哈希值与用户密码的哈希值进行比较

private void Login(object obj)
{
    PasswordBox pwBox = obj as PasswordBox;
    var encryptedPassword = SomeLibrary.EncryptValue(pwBox.Password, someKey);

    if (encryptedPassword == User.EncryptedPassword)
        // Success
}

I'm no expert on the PasswordBoxcontrol or security, but I do know that you don't want to be storing the user's password in plain text anywhere in memory within your application

我不是PasswordBox控制或安全方面的专家,但我知道您不希望将用户密码以纯文本形式存储在应用程序内存中的任何位置

(Technically, it's stored as plain text in PasswordBox.Password- you can use something like Snoopto verify this if you want - however typically the PasswordBox doesn't exist for longer than it takes the user to login, and the actual "password" is just text entered by the user, which may or may not be correct. A keylogger could get you the same information.)

(从技术上讲,它以纯文本形式存储在PasswordBox.Password- 如果需要,您可以使用Snoop 之类的东西来验证这一点 - 但是通常 PasswordBox 的存在时间不会超过用户登录所需的时间,而实际的“密码”只是文本由用户输入,这可能正确也可能不正确。键盘记录器可以为您提供相同的信息。)

回答by Chandramouleswaran Ravichandra

Leaving that article aside - there are a few other posts related to this particular question. You can achieve binding using attached properties. Please see:

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

  1. I believe this question is a duplicate of PasswordBox Binding
  2. The above post points to - http://www.wpftutorial.net/PasswordBox.html
  1. 我相信这个问题是PasswordBox Binding的重复
  2. 上面的帖子指向 - http://www.wpftutorial.net/PasswordBox.html

回答by WiiMaxx

depending on your understanding of mvvm (in my way code behind is allowed in some cases)

取决于您对 mvvm 的理解(以我的方式,在某些情况下允许隐藏代码)

so i create a PasswordBox and also a named TextBlock

所以我创建了一个 PasswordBox 和一个命名的 TextBlock

Xaml

xml

<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" />

codebehind

代码隐藏

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

like you can see your password is save and you can easy bind to it

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

回答by DinoM

I have solved this problem by creating a UserControl that exposes a SecureString dependency property that can be bound to. This method keeps the password in a SecureString at all times, and doesn't "break" MVVM.

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

UserControl

用户控件

XAML

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

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

Example usage

示例用法

Using the control is very straightforward, just bind the password DependencyProperty on the control to a Password property on your ViewModel. The ViewModel's Password property should be a SecureString.

使用该控件非常简单,只需将控件上的密码 DependencyProperty 绑定到 ViewModel 上的 Password 属性即可。ViewModel 的 Password 属性应该是 SecureString。

<controls:PasswordUserControl Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

Change the Mode and UpdateSource trigger on the binding to whatever is best for you.

将绑定上的 Mode 和 UpdateSource 触发器更改为最适合您的触发器。

If you need the password in plain text, the following page describes the proper way to convert between SecureString and string: http://blogs.msdn.com/b/fpintos/archive/2009/06/12/how-to-properly-convert-securestring-to-string.aspx. Of course you shouldn't store the plain text string...

如果您需要纯文本密码,以下页面介绍了 SecureString 和字符串之间的正确转换方法:http: //blogs.msdn.com/b/fpintos/archive/2009/06/12/how-to-properly -convert-securestring-to-string.aspx。当然你不应该存储纯文本字符串......