【问题标题】:Compare Entered Password with Hashed password, Validation Error C# MVC将输入的密码与散列密码进行比较,验证错误 C# MVC
【发布时间】:2016-01-27 11:28:35
【问题描述】:

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

[Required(ErrorMessage = "Enter Password!")]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
public string tPassword { get; set; }

[DataType(DataType.Password)]
[Compare("tPassword", ErrorMessage = "The password and confirmation password does not match.")]
public string Confirmpassword { get; set; }

下一步是对密码进行哈希处理并保存(我使用以下方法创建了一个名为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.")]

谁能向我解释为什么会发生这种情况以及如何解决这个问题?

【问题讨论】:

    标签: c# model-view-controller hash passwords salt


    【解决方案1】:

    您已在 DbContext 上将 ValidateOnSaveEnabled 设置为 true

    context.Configuration.ValidateOnSaveEnabled = true;
    

    这意味着您的验证将被执行两次。首先由模型绑定器(由 MVC 完成) - 这不会引发错误,因为两个密码相同。但是然后在您的 HashAndSavePassword 中,您有纯文本的 ConfirmPassword 和哈希形式的 tPassword。所以当你调用 save 时 EF 会抛出错误。

    你可以:

    1. 通过将 ValidateOnSaveEnabled 设置为 false 来关闭 EF 模型验证。
    2. 在 HashAndSavePassword 函数中还散列 ConfirmPassword 属性(这是 hack)
    3. 实际使用不同的模型,然后转换为 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 类作为参数。这通常不是一个好主意,因为您的数据库模型将具有与注册表单不同的属性集。例如:您的数据库模型上不需要 ConfirmPassword 字段,因为您不需要将其存储在数据库中。并且您的数据库模型将具有永远不应该暴露给视图的属性(例如 IsDeleted、DateModified 等)。因此,最好有一个模型来描述您的视图表单,验证该模型,然后将其转换为不同的数据库或服务模型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-19
    • 2020-08-09
    • 1970-01-01
    • 1970-01-01
    • 2013-08-27
    相关资源
    最近更新 更多