Customising Identity in Razor Pages

3.67 (3 votes)

The code for managing authentication in a Razor Pages application that is provided by the standard project template is a good starting point. However, chances are that you want to customise it to fit your own application needs. This article looks at the most common customisation requirements.

Customising the Registration

A user in ASP.NET Identity is represented by the ApplicationUser class. It has very few properties by default - UserName and Email. The registration form in the template takes the value provided in the Email input and applies it to both the UserName and Email properties. The following steps illustrate how to enable a user to provide a different value for their username:

  1. Add a new property to the InputModel class in the Register.cshtml.cs file for the user name:
    public class InputModel
    {
        [Required]
        [Display(Name = "User Name")]
        public string UserName { get; set; }
        ...
  2. Change the code in the OnPostAsync method so that the value for the user name is assigned from the new property:
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser { UserName = Input.UserName, Email = Input.Email };
        ...
  3. Change the registration form in the Register.cshtml file to accommodate the new property:
    <form asp-route-returnUrl="@Model.ReturnUrl" method="post">
        <h4>Create a new account.</h4>
        <hr />
        <div asp-validation-summary="All" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Input.UserName"></label>
            <input asp-for="Input.UserName" class="form-control" />
            <span asp-validation-for="Input.UserName" class="text-danger"></span>
        </div>
        ...

Adding properties to the ApplicationUser

You probably want to capture more information from the user at the point of registration than just their email address and username. You do this by adding properties to the ApplicationUser class for storing the additional values, and then use Entity Framework Core Migrations to apply the changes to the database so that the additional information can be stored. The following steps show how to add a first name, last name and date of birth fields:

  1. Add two string properties and a DateTime property to the ApplicationUser class:
    public class ApplicationUser : IdentityUser
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime BirthDate { get; set; }
    }
  2. Open the Package Manager Console and type the following command
    PM> add-migration AddedFirstNameLastNameBirthDate
    This will create a migration that, when applied, will modify the schema of the AspNetUsers table in the database to accommodate the additional data related to the properties that have been added.
  3. Apply the migration by typing the following command in the Package Manager Console:
    PM> update-database
  4. Add corresponding properties to the InputModel class (Register.cshtml.cs) together with appropriate annotations for display:
    [Display(Name = "First Name")]
    public string FirstName { get; set; }
    [Display(Name = "Last Name")]
    public string LastName { get; set; }
    [Display(Name = "Date of birth")]
    public DateTime BirthDate { get; set; }
  5. Change the code in the OnPostAsync handler method in the Register.cshtml.cs file to assign values from the Input class to the new ApplicationUser properties:
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser {
            UserName = Input.UserName,
            Email = Input.Email,
            FirstName = Input.FirstName,
            LastName = Input.LastName,
            BirthDate = Input.BirthDate
        };
        ...
  6. Finally, add appropriate additional fields to the form in Register.cshtml
    <div class="form-group">
        <label asp-for="Input.FirstName"></label>
        <input asp-for="Input.FirstName" class="form-control" />
        <span asp-validation-for="Input.FirstName" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Input.LastName"></label>
        <input asp-for="Input.LastName" class="form-control" />
        <span asp-validation-for="Input.LastName" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Input.BirthDate"></label>
        <input asp-for="Input.BirthDate" class="form-control" />
        <span asp-validation-for="Input.BirthDate" class="text-danger"></span>
    </div>

Customising the Password Options

The default password requirements may not suit your purposes:

  • The Password must be at least 6 and at max 100 characters long.
  • Passwords must have at least one non alphanumeric character.
  • Passwords must have at least one lowercase ('a'-'z').
  • Passwords must have at least one uppercase ('A'-'Z').

You can change these defaults via the Razor Pages options in the ConfigureServices method of the Startup class:

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
    {
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 6;
        options.Password.RequireNonAlphanumeric = false;
        options.Password.RequiredUniqueChars = 6;
    })
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

Customising the resources that require authentication

Finally, I look at how to protect resources from non-authenticated users. The default template prevents users from accessing the contents of the Pages/Account/Manage folder, and the Logout action on the AccountController. These are protected by conventions established in the ConfigureServices method of the Startup class:

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        options.Conventions.AuthorizeFolder("/Account/Manage");
        options.Conventions.AuthorizePage("/Account/Logout");
    });

You can protect other resources by adding additional conventions using the AuthorizeFolder method to restrict access to a folder and all of its contents, or the AuthorizePage method to restrict access on a page-by-page basis. Alternatively, you can use the AuthorizeAttribute to protect a specific page. You do this by decorating the page model class for the page with [Authorize]:

[Authorize]
public class AboutModel : PageModel
{
...

Summary

ASP.NET Identity is a comprehensive framework and has a huge range of options. This article has shown how to apply the most commonly used Identity configurations in a Razor Pages application. In my next article, I will look at adding simple authentication to Razor Pages without using ASP.NET Identity.

You might also like...

Date Posted:
Last Updated:
Posted by:
Total Views to date: 552

0 Comments

Recent Comments

Pam 30/08/2017 11:30
In response to Sending Email in Razor Pages
Mike, RazorPages sound like a nice choice for somebody still working in ASP classic who wants to to...

Robby Robson 15/08/2017 00:43
In response to Routing in Razor Pages
Mike: great stuff. Now that .Core Standard 2.0 is formally out, how soon will you rewrite your book...

Satyabrata Mohapatra 28/07/2017 08:59
In response to Sending Email in Razor Pages
Bit off topic, but congratulation sir for your MVP award. You deserve it !!!...

Satyabrata Mohapatra 23/07/2017 16:43
In response to Razor Pages - The Elevator Pitch
@Dale Severin You can continue to build apps using asp.net web pages....

Satyabrata Mohapatra 23/07/2017 16:40
In response to Sending Email in Razor Pages
Thanks for sharing...learned a lot...

Gfw 22/07/2017 11:53
In response to Sending Email in Razor Pages
Question... Does System.Net.Mail support SSL?...

Dale Severin 20/07/2017 03:38
In response to Razor Pages - The Elevator Pitch
I work with razor web pages extensively. I appreciate the rapid development it permits me to I am as...

Obinna Okafor 14/07/2017 01:19
In response to Routing in Razor Pages
Thank you, Mike. Good post....

Satyabrata Mohapatra 11/07/2017 16:02
In response to Routing in Razor Pages
Very powerful routing system!!...

Cyrus 05/07/2017 03:41
In response to Razor Pages - Getting Started With The Preview
How can I trim packages and services as much as possible to use just razor pages? I don’t want to to...