如何使用与定义模型不同的格式更新密码?我收到了DbEntityValidationException

时间:2015-04-10 16:32:48

标签: c# asp.net-mvc-5 entity-framework-6

问题

  • 我的Code-First模型有一个预先定义的[StringLength()][RegularExpression()]约束。
  • [StringLength()]要求为8-16个字符
  • 密码的[RegularExpression()]约束与加密密码的格式不同。
    • 密码在被推入数据库之前已加密。
    • 加密密码长度为70个字符,高于模型中定义的8-16个字符限制。
  • 我需要使用e.Encrypt(),这意味着我无法使用默认的ASP.NET哈希算法。

我已经搜索过高低,但尚未找到正确的答案。

我的代码

我有一个允许用户注册帐户的功能。它看起来像这样:

[HttpPost]
public ActionResult Register([Bind(Include="Username,Password,EmailAddress")] UserModel user)
{
    if (TryUpdateModel(user))
    {
        // Set password to a different format than Model's designated Regex
        user.Password = e.Encrypt(user.Password);

        context.Entry(user).State = EntityState.Added;
        context.SaveChanges();
        return RedirectToAction("Login", "Account");
    }
    return View();
}

在我的UserModel.cs文件中,我有以下限制:

    [Required]
    [DataType(DataType.Password)]
    [StringLength(16, MinimumLength = 8, ErrorMessage = "Must be between 8 and 16 characters.")]
    [RegularExpression("^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]", ErrorMessage = ErrorMessage_PasswordRegex)]
    public string Password { get; set; }

同样,散列密码的格式完全不同。因此,我无法更新它,因为它会抛出DbEntityValidationException。此[RegularExpression()]用于用户密码的格式。我需要能够绕过或暂停密码的Regex约束。

我采取了哪些措施来解决这个问题

我已删除[RegularExpression()]要求,并将[StringLength()]上升到70,这是我的密码哈希的长度。

但是,我不想让用户输入70个字符的文字。这似乎是一个廉价的黑客,我觉得应该有一个更好的方法来做到这一点。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

以下是一个例子:

我们对用户输入的要求与我们的数据库要求不同。我们可能需要更多用户输入,我们将以编程方式对其进行操作。

EF模型

public class UserModel()
{
    [Key]
    public string Id { get; set; }

    public string Name { get; set; }

    [Required, StringLength(70)]
    public string Password { get; set; }
}

现在这是我们用来捕获用户输入的类

public class UserViewModel()
{
    [Required]
    public string Name { get; set; }

    [Required]
    [RegularExpression("^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]", ErrorMessage = ErrorMessage_PasswordRegex)]
    public string Password { get; set; }

    [Required]
    public string ConfirmPassword { get; set; }
}

现在我们转换并映射值。

用户不知道Id的用途,数据库不需要ConfirmPassword。我们还可以将用户最初输入的内容转换为密码。

[HttpPost]
public ActionResult Register(UserViewModel model)
{
    if ((ModelState.IsValid) &&
        (model.Password == model.ConfirmPassword))
    {
        // map to EF model
        var user = new UserModel
        {
            Name = model.Name,
            Password = e.encrypt(model.Password)  // transform, encrypt, whatever
        };

        db.Users.Add(user);  // use EF model to persist
        ...

        return RedirectToAction("Login", "Account");
    }
    return(model);
}