How do I update a password that's in a differe

2019-08-06 09:04发布

The Problem

  • I have a pre-defined [StringLength()] and [RegularExpression()] constraint on my Code-First Model.
  • The [StringLength()] requirement is 8-16 characters
  • The [RegularExpression()] constraint for the password is in a different format from the encrypted password.
    • The password is encrypted before being shoved into the database.
    • The encrypted password is 70 characters in length, which is higher than the 8-16 character limit defined in the Model.
  • I am required to use e.Encrypt(), meaning I cannot use the default ASP.NET hashing algorithm.

I've searched high and low, but have yet to find the correct answer.

My Code

I have a function that allows a user to register an account. It looks like this:

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

In my UserModel.cs file, I have the following constraints:

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

Again, the hashed password is in a completely different format. Therefore, I cannot update it because it throws a DbEntityValidationException. This [RegularExpression()] is for the format of the user's password. I need to be able to bypass or suspend the password's Regex constraint.

What I have done to remedy this

I've removed the [RegularExpression()] requirements, and upped the [StringLength()] to 70, which is the length of my password hash.

However, I don't want to allow users to input 70 characters of text. This seems like a cheap hack, and I feel that there should be a better way to do this. Any ideas?

1条回答
▲ chillily
2楼-- · 2019-08-06 09:36

Here's an example:

We've got different requirements for user input than what our database requires. We might need more user input which we will programmatically act upon.

The EF model

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

    public string Name { get; set; }

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

Now here's the class we use to capture user input

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

Now we transform and map values.

The user won't know what to use for Id and the database doesn't have need for ConfirmPassword. We can also transform what the user originally entered as a password.

[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);
}
查看更多
登录 后发表回答