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

Compare Entered Password with Hashed password, Validation Error C# MVC

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

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

下一步是对密码进行哈希处理并保存(我创建了一个新的class名为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);
}

然后在控制器中,我使用以下方法调用负责密码散列的方法,然后将用户数据保存到 Entity Framework:

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。因此当您调用保存时 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);
}