C# 通过将linq查询分配给字符串类型的单个变量,是否有任何方法可以清理代码?

C# 通过将linq查询分配给字符串类型的单个变量,是否有任何方法可以清理代码?,c#,sqlite,linq,C#,Sqlite,Linq,我为一个我一直在做的项目做了一个登录系统,虽然它可以工作,但它看起来并不是我能做的最有效的方式。这是一个WPF/C项目,链接到使用LINQ进行查询的SQLite数据库。理想情况下,我希望查询输出一个字符串类型的变量,这样我就可以操作它,并将其与用户输入的内容进行比较 List<Engineer> engineers; private void LoginButton_Click(object sender, RoutedEventArgs e) {

我为一个我一直在做的项目做了一个登录系统,虽然它可以工作,但它看起来并不是我能做的最有效的方式。这是一个WPF/C项目,链接到使用LINQ进行查询的SQLite数据库。理想情况下,我希望查询输出一个字符串类型的变量,这样我就可以操作它,并将其与用户输入的内容进行比较

List<Engineer> engineers;
private void LoginButton_Click(object sender, RoutedEventArgs e)
        {
            string username = UsernameField.Text;
            string password = PasswordField.Password.ToString();
            string hashedPasswordString = "";
            string saltString = "";

            //establishes connection
            using (SQLiteConnection conn = new SQLiteConnection(App.engineerDatabasePath))
            {

                engineers = conn.Table<Engineer>().ToList();
                //Queries for a list containing the respective hashed passwords. This will only contain one password since the emails are unique
                var hashedpasswordlist = from c in engineers
                                     where c.Email == username
                                     select c.Password;

                //Take the password in the list and assign it to a string variable that can be compared
                foreach (var item in hashedpasswordlist)
                {
                    hashedPasswordString = item;
                }

                //Queries for a list containing the respective salts. This will only contain one salt since the emails are unique
                var saltlist = from c in engineers
                               where c.Email == username
                               select c.Salt;

                //Take the salt in the list and assign it to a variable to the password input, creating a hash value that is to be assigned
                foreach (var item in saltlist)
                {
                    saltString = item;
                }

                //Confirmation that the implementation works as it should
                if (GenerateSHA256Hash(password, saltString) == hashedPasswordString) 
                {
                    MessageBoxResult deleteConfirmation = MessageBox.Show("IT WORKS!", "Grats", MessageBoxButton.YesNo, MessageBoxImage.Warning);
                }

            }
            //Allows you to log in regardless of whether your login details are correct. This is the case for testing purposes.
            MainWindow MainWindow = new MainWindow();
            MainWindow.Show();
            this.Close();
        }

你可以使用你的第一行,并在此基础上构建

engineers = conn.Table<Engineer>().ToList();



var engineer = conn.Table<Engineer>().First(x=>x.Email.Equals(username)); 

var password = conn.Table<Engineer>().First(x=>x.Email.Equals(username)).Password;

var saltString = engineer.Salt

var pw = engineer.Password

如果您想要检索实际密码并将其与用户输入的密码进行比较,则不应这样做。出于安全原因,密码不应以可检索的格式存储在数据库中,因此对输入的密码进行散列并将其与数据库中的散列进行比较要比直接比较安全得多,效率也不会低得多

也就是说,您可以在一个步骤中检索salt和哈希,并使用SingleOrDefault,因为您只需要一项:

//Queries for a list containing the respective hashed passwords. This will only contain one password since the emails are unique
var saltedPassword = (from c in conn.Table<Engineer>()
                     where c.Email == username
                     select new {c.Password, c.Salt}).SingleOrDefault();

//TODO: Add handling for when password is not found (saltedPassword is null)

hashedPasswordString = saltedPassword.Password;
saltString = saltedPassword.Salt;
您正在查询Engineer表,因此很明显返回的是Engineer对象,并且由于您正在查询同一个对象,因此需要查询该表,以Engineer对象的形式获取结果,然后浏览其属性

无需多次查询,只需查询一次即可

private void LoginButton_Click(object sender, RoutedEventArgs e)
{
    // Basic null handling 
    if(string.IsNullOrEmpty(UsernameField.Text)) { throw new ArgumentNullException(nameof(UsernameField.Text)); }

    if(string.IsNullOrEmpty(PasswordField.Password?.ToString())) { throw new ArgumentNullException(nameof(UsernameField.Text)); }

    //establishes connection
    using (SQLiteConnection conn = new SQLiteConnection(App.engineerDatabasePath))
    {
        // get the Engineer object
        var engineer = conn.Table<Engineer>().FirstOrDefault(c => c.Email.Equals(UsernameField.Text, StringComparison.OrdinalIgnoreCase));

        // generate the password
        var password = GenerateSHA256Hash(PasswordField.Password.ToString(), engineer.Salt); 

        //Confirmation that the implementation works as it should
        if (engineer.Password.Equals(password))
        {
            MessageBoxResult deleteConfirmation = MessageBox.Show("IT WORKS!", "Grats", MessageBoxButton.YesNo, MessageBoxImage.Warning);
        }

    }
    //Allows you to log in regardless of whether your login details are correct. This is the case for testing purposes.
    MainWindow MainWindow = new MainWindow();
    MainWindow.Show();
    this.Close();
}

因此,我采用@D Stanley的方法,并将其与@iSR5缺少变量相结合,创建了以下内容:

using (SQLiteConnection conn = new SQLiteConnection(App.engineerDatabasePath))
                {

                    var saltedPassword = (from c in conn.Table<Engineer>()
                                          where c.Email == UsernameField.Text
                                          select new { c.Password, c.Salt }).SingleOrDefault();

                    if (saltedPassword != null)
                    {
                        if (GenerateSHA256Hash(PasswordField.Password.ToString(), saltedPassword.Salt) == saltedPassword.Password)
                        {
                            MessageBox.Show("Correct credentials, click ok to continue", "Access Granted", MessageBoxButton.OK);
                            MainWindow MainWindow = new MainWindow();
                            MainWindow.Show();
                            this.Close();
                        }
                    }
                    else
                    {
                        MessageBox.Show("Incorrect credentials", "Error", MessageBoxButton.OK, MessageBoxImage.Information);
                    }

                }
似乎当找不到电子邮件时,saltedPassword最终将为null,因此我还编写了一个if语句,以确保程序在发生这种情况时不会崩溃。我曾考虑冒险使用lambda表达式并抛出null异常,但我对编程还是相当陌生,缺乏这些方面的知识


谢谢大家:

工程师们也应该在conn.Table中不使用ToList,因为这样可以避免只为了一个条目而加载整个表格。@ckuri很好,我没有注意到这一点。
using (SQLiteConnection conn = new SQLiteConnection(App.engineerDatabasePath))
                {

                    var saltedPassword = (from c in conn.Table<Engineer>()
                                          where c.Email == UsernameField.Text
                                          select new { c.Password, c.Salt }).SingleOrDefault();

                    if (saltedPassword != null)
                    {
                        if (GenerateSHA256Hash(PasswordField.Password.ToString(), saltedPassword.Salt) == saltedPassword.Password)
                        {
                            MessageBox.Show("Correct credentials, click ok to continue", "Access Granted", MessageBoxButton.OK);
                            MainWindow MainWindow = new MainWindow();
                            MainWindow.Show();
                            this.Close();
                        }
                    }
                    else
                    {
                        MessageBox.Show("Incorrect credentials", "Error", MessageBoxButton.OK, MessageBoxImage.Information);
                    }

                }