Customising Identity in Razor Pages

3.83 (6 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: 1615

3 Comments

- Satyabrata Mohapatra

Thanks for sharing. Learned a lot!!

- Rachida

Thanks very much for this wonderful tutorial, it helped a lot.

- rachida Dukes

Thanks again for this wonderful tutorial.
I followed all the steps in this section called:
Adding properties to the ApplicationUser

But one little is missing,:
when the user is updating the first name or last name or birthday, which code can we add to save the changes in the profile section -meaning in the file pages\Account\Manage\Index.cshtml.cs

Thanks,

Recent Comments

Borut 17/02/2018 12:59
In response to I'm Not Writing A Book On Razor Pages
Mike, is it possible that Web Pages and Razor Pages "live" together in one web application? I a I...

hrboyce 09/02/2018 04:44
In response to I'm Not Writing A Book On Razor Pages
Mike, First thanks for doing this but I have to ask, any chance you would consider converting one of...

aziz sallam 07/02/2018 10:18
In response to I'm Not Writing A Book On Razor Pages
u are a great man...

Satyabrata Mohapatra 31/01/2018 11:36
In response to I'm Not Writing A Book On Razor Pages
This is a great news!!!! Thanks...

tangdf 30/01/2018 07:25
In response to I'm Not Writing A Book On Razor Pages
=> { o.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute()); }); The extension method does...

Obinna Okafor 30/01/2018 04:02
In response to I'm Not Writing A Book On Razor Pages
Thank you very much. I would like to see a project built from scratch using Razor Pages. And it show...

rachida Dukes 31/10/2017 13:52
In response to Customising Identity in Razor Pages
Thanks again for this wonderful tutorial. I followed all the steps in this section called: Adding...

Rachida 31/10/2017 12:06
In response to Customising Identity in Razor Pages
Thanks very much for this wonderful tutorial, it helped a lot....

Satyabrata Mohapatra 13/10/2017 10:17
In response to Customising Identity in Razor Pages
Thanks for sharing. Learned a lot!!...

Cyrus 23/09/2017 11:44
In response to Routing in Razor Pages
I want to have dynamic sitemap in my razor page app so I've created a page named "SiteMap" and route...