Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将输入的密码与哈希密码进行比较,验证错误C#MVC_C#_Model View Controller_Hash_Passwords_Salt - Fatal编程技术网

将输入的密码与哈希密码进行比较,验证错误C#MVC

将输入的密码与哈希密码进行比较,验证错误C#MVC,c#,model-view-controller,hash,passwords,salt,C#,Model View Controller,Hash,Passwords,Salt,我正在尝试使用MVC模式制作一个表单来注册新用户并将数据保存到实体框架中;问题是,我正在尝试比较输入的密码,如下所示(代码是在模型中编写的) 下一步是散列密码并保存它(我使用以下方法创建了一个名为Security的新类,以及验证密码的其他方法),代码如下: public static void HashAndSavePassword(string password, RegisterTable usr) { var v = new Rfc2898DeriveBytes(password,

我正在尝试使用MVC模式制作一个表单来注册新用户并将数据保存到实体框架中;问题是,我正在尝试比较输入的密码,如下所示(代码是在模型中编写的)

下一步是散列密码并保存它(我使用以下方法创建了一个名为Security的新类,以及验证密码的其他方法),代码如下:

public static void HashAndSavePassword(string password, RegisterTable usr)
{
    var v = new Rfc2898DeriveBytes(password, 16, 3987);
    usr.tPassword = Convert.ToBase64String(v.GetBytes(25), Base64FormattingOptions.None);
    usr.Salt = Convert.ToBase64String(v.Salt, Base64FormattingOptions.None);
}
然后在控制器中,我使用以下方法调用负责密码哈希的方法,然后将用户数据保存到实体框架中:

public ActionResult Register(RegisterTable user)
{
    if (ModelState.IsValid)
    {
         // To check if username already exist
         var searchUserName = db.RegisterTables.Where(x => x.tUserName.Equals(user.tUserName)).FirstOrDefault();

         if (searchUserName == null)
         {
             Security.HashAndSavePassword(user.tPassword, user);

             db.RegisterTables.Add(user);
             db.SaveChanges();
             ModelState.Clear();
             return RedirectToAction("Login");
         }
         else ModelState.AddModelError("", "User is already Registred.");            
     }

     return View(user);
 }
问题是,我在运行代码时遇到以下错误:

但如果我删除此行,代码将正常工作:

[Compare("tPassword", ErrorMessage = "The password and confirmation password does not match.")]

有人能给我解释一下为什么会发生这种情况以及如何解决这个问题吗?

您已经在DbContext中将ValidateOnSaveEnabled设置为true

context.Configuration.ValidateOnSaveEnabled = true;
这意味着您的验证将执行两次。首先由模型绑定器(由MVC完成)-这不会抛出错误,因为两个密码相同。但是,在HashAndSavePassword中,您有明文形式的ConfirmPassword和哈希形式的tPassword。因此,当您调用save时,EF将抛出错误

你可以:

  • 通过将ValidateOnSaveEnabled设置为false来关闭EF模型验证
  • 在HashAndSavePassword函数中,还可以使用hash ConfirmPassword属性(这是hack)
  • 在操作中使用不同的模型,然后转换为EF中使用的模型。(本文件已提交)

  • 你的数据库模型

    public class RegisterTable
    {
        public int Id { get; set; }
        public string tPassword { get; set; }
        public string tUserName { get; set; }
        public string Salt { get; set; }
    
        ...
    }
    

    您的视图模型:

    public class RegisterModel
    {
        // put username validation rules here
        public string UserName { get; set; }
    
        [Required(ErrorMessage = "Enter Password!")]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    
        [DataType(DataType.Password)]
        [Compare("Password", ErrorMessage = "The password and confirmation password does not match.")]
        public string Confirmpassword { get; set; }
    
        ...
    
        public RegisterTable Map()
        {
            var v = new Rfc2898DeriveBytes(this.Password, 16, 3987);
            return new RegisterTable()
            {
    
                Salt = Convert.ToBase64String(v.Salt, Base64FormattingOptions.None),
                tPassword = Convert.ToBase64String(v.GetBytes(25), Base64FormattingOptions.None),
                tUserName = this.UserName
            };
        }
    }
    

    你的行动

    public ActionResult Register(RegisterModel user)
    {
        if (ModelState.IsValid)
        {
            // To check if username already exist
            var searchUserName = db.RegisterTables.Where(x => x.tUserName.Equals(user.UserName)).FirstOrDefault();
    
            if (searchUserName == null)
            {
                var dbUser = user.Map();
    
                db.RegisterTables.Add(user);
                db.SaveChanges();
                ModelState.Clear();
                return RedirectToAction("Login");
            }
            else ModelState.AddModelError("", "User is already Registred.");
        }
    
        return View(user);
    }
    

    谢谢,这很有效,但我不明白第三点,你把一个模型转换成EF模型是什么意思,你能提供更多的信息或者一个好的教程来解释它吗?再次感谢您现在使用RegisterTable类作为Register操作中的参数。这通常不是一个好主意,因为您的DB模型的属性集与您的注册表不同。例如:您的DB模型上不需要ConfirmPassword字段,因为您不需要将其存储在DB中。并且,您的数据库模型将具有一些属性,这些属性永远不会向视图公开(例如IsDeleted、DateModified等)。所以,最好使用描述视图表单的模型,验证该模型,然后将其转换为不同的数据库或服务模型。
    public ActionResult Register(RegisterModel user)
    {
        if (ModelState.IsValid)
        {
            // To check if username already exist
            var searchUserName = db.RegisterTables.Where(x => x.tUserName.Equals(user.UserName)).FirstOrDefault();
    
            if (searchUserName == null)
            {
                var dbUser = user.Map();
    
                db.RegisterTables.Add(user);
                db.SaveChanges();
                ModelState.Clear();
                return RedirectToAction("Login");
            }
            else ModelState.AddModelError("", "User is already Registred.");
        }
    
        return View(user);
    }