This page is a work in progress.You can help improve it. →

# Setting up for Users

To keep track of the user that created restaurants and reviews, we will need to add the idea of users and login/logout features.

We will create a user model and the associated controller to manage them. Then we will make user interface components for creating accounts and for logging in.

## User Model

To begin, create a user model that stores information about the user. Each user will have the following attributes:

• Id
• Full Name

It is unwise to store unencrypted passwords in our database. Thus we will not keep the raw password, but a hashed password.

The idea of a hashed password relies on the concept of a "one-way function", that is a function that is fast and easy to compute in one direction but difficult to calculate in the other.

Let us take a look at the idea of a "two-way function". A simple example would be `double`, which takes a number and multiplies it by two. If I give you the input of this function, say `42`, you can quickly and reliably compute the output, `84`. If I provide you with output, say `246`, it is trivial for you to figure out what a corresponding input would be: `123`. This process would be simple regardless of the size of the numbers. Given `24686850904684`, you can quickly figure out what the corresponding input is.

A classic example of a one-way function is the prime factorization function. Given two prime numbers, say `17` and `5`, it is easy to multiply them together and get `85`. Given a number like `85`, it isn't too hard to figure out which two prime numbers multiply together to get that number. This isn't true as the number gets larger. If I give you the number `682654107378822049` it isn't so trivial to compute the two numbers that are its prime factors (the answer is `982451653` and `694847533`)

For something like a password, we will use the idea of a `hashing function`. A `hashing function` attempts to take an input value and compute a fixed size and mostly unique value. Small changes in the input should make a large and unpredictable change in the output.

A popular hashing function is `SHA256`. If we take the text `dotnet` and process it with this algorithm we get back out the result: `3831fff4af76125e90081ac7eb855a1bcce0733045f9d26cd620466e0d4acf97`. If we take the text `ditnet`, just one letter different we get `fb89fe75f8be03f17435f563121e940360cd9fcfcbd3f8978b59c160fdaca711`

Given a result of a `SHA256` hash, it is very difficult to work out what text generated it.

We will be using the built-in `dotnet` hashing algorithm based on `PBKDF2`, a strong password hashing algorithm.

## Defining our model

We will want to treat the `Id`, `FullName`, and `Email` as we have other fields for our model. For the password, we will be creating and storing a `HashedPassword` in the database. Mark this field as `JsonIgnore` so it skipped by serialization and not exposed in any API results.

We also wish to be able to assign a plain text password to a user. The setting of this plain text password should have the effect of hashing that value and storing it in the `HashedPassword` property. We will also need a way to validate a user password.

``using System.ComponentModel.DataAnnotations;using System.Text.Json.Serialization;using Microsoft.AspNetCore.Identity;namespace TacoTuesday.Models{    public class User    {        public int Id { get; set; }        [Required(ErrorMessage = "You must provide your name")]        public string FullName { get; set; }        [Required(ErrorMessage = "You must provide your email")]        public string Email { get; set; }        [JsonIgnore]        public string HashedPassword { get; set; }        // Define a property for being able to _set_ a password        public string Password        {            // Define only the `set` aspect of the property            set            {                // When set, use the PasswordHasher to encrypt the password                // and store the result in our HashedPassword                this.HashedPassword = new PasswordHasher<User>().HashPassword(this, value);            }        }        // Add a method that can validate this user's password        public bool IsValidPassword(string password)        {            // Look to see if this password, and the user's hashed password can match            var passwordVerification = new PasswordHasher<User>().VerifyHashedPassword(this, this.HashedPassword, password);            // Return True if the verification was a success            return passwordVerification == PasswordVerificationResult.Success;        }    }}``

We will also mark the `FullName` and the `Email` as required since we'll use the email as the login, and we want to be able to address the user by name.

This class uses a custom `setter` for the `Password`, allowing us to set it from the API. That setter hashes the password and assigns the user's `HashedPassword` property (stored in the database)

We also have a method `IsValidPassword` that can identify if we have a valid password.

## Generating a migration

Add the `Users` to the `DatabaseContext` class:

``// Tell the context about the User collection/tablepublic DbSet<User> Users { get; set; }``

``dotnet ef migrations add CreateUserModel``
``dotnet ef database update``