Authorization In Razor Pages ASP.NET Core

Introduction

Authorization is a process that determines what a user is able to do. For example, an Admin user is allowed to install/remove software from a computer and a non-Admin user can use the software from the computer. It is independent and orthogonal from authentication. However, authorization requires an authentication mechanism. For applications, the first step is always authentication and then authorization.

Using AuthorizeFilter, we can control the access in our MVC / Web API application by specifying this attribute in the controller or action method. Similarly, there is a way to control access in our Razor pages, i.e., to use authorization conventions at startup. These conventions allow us to authorize users to access individual pages or folders of the pages. In the same way, these conventions allow anonymous users to access individual pages or folders of pages.

To demonstrate the concept, I have created an application with ASP.NET Core Identity. For guidance on how to create an application with ASP.NET Core Identity, please refer to my article "Overview Of Identity In ASP.NET Core 2.0".

Using AddRazorPagesOptions, we can add an AuthorizeFilter to the page at the specified path. With AddRazorPagesOptions, we have a couple of methods that can be used to authorize or allow anonymous access to the page or folder.

AuthorizePage

This adds an AuthorizeFilter to the specified page. There are two extension methods: one is "to accept the page name" and the other one is " to accept the page name and authorization policy".

public static PageConventionCollection AuthorizePage(
    this PageConventionCollection conventions, 
    string pageName)    
public static PageConventionCollection AuthorizePage(
    this PageConventionCollection conventions, 
    string pageName, 
    string policy)

AuthorizeFolder

This adds AuthorizeFilter to all pages under a specified folder. There are two extension methods - accept the folder path, and accept the folder path and authorization policy.

public static PageConventionCollection AuthorizeFolder(this PageConventionCollection conventions, string folderPath)  
public static PageConventionCollection AuthorizeFolder(this PageConventionCollection conventions, string folderPath, string policy)  

AllowAnonymousToPage

This adds AllowAnonymousFilter to the specified page.

public static PageConventionCollection AllowAnonymousToPage(
    this PageConventionCollection conventions, 
    string pageName)

AllowAnonymousToFolder

This adds AllowAnonymousFilter to all the pages under the specified folder.

public static PageConventionCollection AuthorizeAreaPage(
    this PageConventionCollection conventions, 
    string areaName, 
    string pageName)
{
    // Implementation code here
}

public static PageConventionCollection AuthorizeAreaPage(
    this PageConventionCollection conventions, 
    string areaName, 
    string pageName, 
    string policy)
{
    // Implementation code here
}

AuthorizeAreaPage

This is the same as the AuthorizePage method. It adds AuthorizeFilter to the specified page under the specified Area. It also has an extension method that accepts the authorization policy.

public static PageConventionCollection AuthorizeAreaPage(
    this PageConventionCollection conventions, 
    string areaName, 
    string pageName)
{
    // Method implementation here
}

public static PageConventionCollection AuthorizeAreaPage(
    this PageConventionCollection conventions, 
    string areaName, 
    string pageName, 
    string policy)
{
    // Method implementation here
}

AuthorizeAreaFolder

This is the same as the AuthorizeFolder method. It adds AuthorizeFilter to all the pages under the specified folder under the specified Area. It also has an extension method that accepts the authorization policy.

public static PageConventionCollection AuthorizeAreaFolder(
    this PageConventionCollection conventions, 
    string areaName, 
    string folderPath)
{ 
    // Method implementation
}
public static PageConventionCollection AuthorizeAreaFolder(
    this PageConventionCollection conventions, 
    string areaName, 
    string folderPath, 
    string policy)
{ 
    // Method implementation
}

AllowAnonymousToAreaPage

This adds AllowAnonymousFilter to the specified page that is located under the specified area.

public static PageConventionCollection AllowAnonymousToAreaPage(
    this PageConventionCollection conventions, 
    string areaName, 
    string pageName)

AllowAnonymousToAreaFolder

This adds AllowAnonymousFilter to all the pages that are located under the specified area folder.

public static PageConventionCollection AllowAnonymousToAreaFolder(
    this PageConventionCollection conventions,
    string areaName,
    string folderPath)
{
    // Implementation here
}

Example

To demonstrate the concept, I have created a few pages and the following snippet shows the folder structure of defined authorization in the project.

WebApplication

public void ConfigureServices(IServiceCollection services)  
{  
    ....  
    ....  
    services.AddMvc().AddRazorPagesOptions(options =>  
    {  
        options.Conventions.AuthorizePage("/Page3");  
        options.Conventions.AuthorizeFolder("/Public");  
        options.Conventions.AllowAnonymousToPage("/page4");  
        options.Conventions.AllowAnonymousToFolder("Private");  
        options.Conventions.AuthorizeAreaPage("MyFeature", "/AuthPage1");  
        options.Conventions.AllowAnonymousToAreaPage("MyFeature", "/AuthPage2");  
    })  
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);  
}  

The authorization conventions can be also applied to Razor class Library.

public void ConfigureServices(IServiceCollection services)  
{  
    ....  
    ....  
    services.AddMvc().AddRazorPagesOptions(options =>  
    {  
        ....  
        ....  
        // This page is defined in Razor Class Library project  
        options.Conventions.AuthorizeAreaPage("MyFeature", "/Page1");  
        ....  
        ....  
    })  
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);  
}  

Combining authorized and anonymous access

We can also specify authorization for the folder and within this folder, it allows anonymous access.

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        // ...
        options.Conventions.AuthorizeFolder("/Private")
            .AllowAnonymousToPage("/Private/page8");
        // ...
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

The reverse case is not allowed; i.e., we cannot define a folder for anonymous access and specify a page within it for authorization. In this case, AllowAnonymousFilter is always applied and AuthorizeFilter is ignored.

.AllowAnonymousToFolder("/Private")
.AuthorizePage("/Private/page8");

Summary

Using this authorization convention, we can apply authorization on Razor pages. This convention can also be applied to Razor class Library (RCL) project if we use it in our project. In the case of RCL, the conventions are defined in the project that used RCL.

You can view or download the source code from the GitHub link here.