简体   繁体   中英

ASP.NET Core model binding on Controller with a private property getter (for Password)

I have this simple User Class and for the Password property I want to make the getter private (only used internally - exposing a public VerifyPassword method that will perform a verification internally and return a boolean)

Now the question comes with model binding on a route in my Controller. When I try to use the asp-for tag helper to point at the Model.Password it tells me that "Password can not be used in this context because the get-accessor is unavailable"

I am a beginner. I thought making the getter private was a smart move to protect it from being exposed. But now I can not use it in the model binding.

So a few questions: Is this the correct way of protecting the Password? Is this the correct way of using model binding? Any suggestions on how this can be improved?

Here is the model:

    using System;

namespace user_signup.Models {
    public class User
    {
        private string username;
        private string email;
        private string password;

        public string Username { 
            get => username;
            set {
                if (value.Length < 5) {
                    throw new ArgumentException("Username is too short.");
                }
                if (value.Length > 15) {
                    throw new ArgumentException("Username is too long.");
                }
                username = value;
            }
        }
        public string Email {
            get => email;
            set {
                // email validation here
                email = value; 
            }
        }

        public string Password {
            // the getter is private (only accessable internally)
            private get => password;
            set {
                if (value.Length < 5) {
                    throw new ArgumentException("Password is too short.");
                } 
                if (value.Length > 15) {
                    throw new ArgumentException("Password is too long.");
                }

                password = value;
            }
        }

        // public means of verifying a password (the password itself is never exposed)
        public bool VerifyPassword(string pass) => Password.Equals(pass);


        // counter of all users that have been instantiated (prevents overlapping IDs)
        // static so it is at the Class level (can be counted globally outside of all User instances)
        private static int NextId = 0;

        // can only be set internally (private setter)
        // defaults to the CURRENT VALUE of NextId and THEN increments NextId for the next instantiation
        public int UserId { get; } = NextId++;

        // can only be set internally (private setter)
        // defaults to current DateTime in string format
        public string CreateDate { get; private set; } = DateTime.Now.ToString(); 

        // the model will be populated from form data sent in a Request
        public User() {}

        // for creating a user by other means (manually)
        public User(string u, string e, string p) {
            Username = u;
            Email = e;
            Password = p;
        }

        public override string ToString() {
            return String.Format(
                "UserId: {0}\nUsername: {1}\nEmail: {2}\n\n",
                UserId,
                Username,
                Email
            );

        }
    }
}

Here is the Controller (specifically the Add.cshtml GET and POST handlers)

    [HttpGet]
    public IActionResult Add() {
        VModel.User = new User();
        return View(VModel);
    }

    [HttpPost]
    public IActionResult Add(User user, string verify) {
        VModel.User = user;
        VModel.Users = Users.GetUsers();
        if (!user.VerifyPassword(verify)) {
            VModel.Errors["verify"] = "Verify password failed. Passwords do not match.";
            return View(VModel);
        }

        return View("Index", VModel);

    }

and finally the Add.cshtml View

@using user_signup.Controllers
@model UserController.ViewModel

<!DOCTYPE html>

<html>
<head>
    <title>title</title>
</head>
<body>
<div>
    <form  asp-controller="User" asp-action="Add" method="post">
        <label>Username: </label>
        <input type="text" asp-for="@Model.User.Username" required/>

        <label>Email: </label>
        <input type="text" asp-for="@Model.User.Email"/>

        <label>Password: </label>
        <input type="password" asp-for="@Model.User.Password" required/>

        <label>Verify Password: </label>
        <input type="password" name="verify" required/>

        <input type="submit" value="Sign Up"/>

    </form>
</div>
</body>
</html>
  • Do not store password as plain text in database
  • Use ASP.NET Identity for managing Auth
  • Do not use Domain Entities ( User in this case) directly in View, instead use ViewModel
  • User Fluent Validation for validating user input

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM