In this tutorial, we will show you how to implement basic Authorization using Authorize attribute. The Authorize attribute restricts the unauthenticated user from accessing the URL. You can override it with AllowAnonymous attribute. Our example will use both MVC & Razor Pages. The Web API Projects also use the same techniques to protect the API Endpoints.
Table of Contents
We use Authorize attribute to decorate a controller, action, or Razor page. This will limit access to that only to the authenticated user. The unauthenticated users are redirected to the login page.
For example, the following code limits access to the AccountController only to the authenticated users.
[Authorize]
public class AccountController : Controller
{
public ActionResult Login()
{
}
public ActionResult Logout()
{
}
}Example Project
Create a new ASP.NET Core Web App (MVC) using VS2019. Name the app as AuthzExample. Choose .NET 5.0 & Individual Accounts.
Update the appsettings.json with the connection string.
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=AuthzExample;Trusted_Connection=True;MultipleActiveResultSets=true"
},Create a new entity Product under the folder Data
Data/Product.cs
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations.Schema;
namespace AuthzExample.Data
{
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
[ForeignKey("IdentityUser")]
public string CreatedUserID { get; set; }
public IdentityUser User { get; set; }
}
}Add DbSet Property in ApplicationDbContext
Data/ApplicationDbContext.cs
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace AuthzExample.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Product> Products { get; set; }
}
}Run the add-migration & update-database to create the database
add-migration product
update-databaseTo Manage the Products, we will create both MVC & Razor Page versions of the page.
Create a new MVCProductsController using the template MVC Controller using Views, Using Entity Framework. Model class as Product & Data Context class as ApplicationDbContext. Layout Page as ~/Views/Shared/_Layout.cshtml. Controller Name MVCProductsController

Create a new folder Pages/RazorProducts. Add a Razor Page using the template Razor Pages using the Entity Framework (CRUD). Model class as Product & Data Context class as ApplicationDbContext. Layout page as ~/Views/Shared/_Layout.cshtml

Under the Pages, folder add the _ViewImports.cshtml file with the following code
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpersAdd the navigation link to both the pages in the _Layout.cshtml after the Home menu.
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="MVCProducts" asp-action="Index">Products (MVC)</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/RazorProducts/Index">Products (Razor) </a>
</li>Open the startup class and add the following code to enable Razor Pages
services.AddRazorPages();Run the app, you should be able to access all the pages including the Products page without login.
Now, let us secure the Products Page.
Securing a MVC/API Controller
Add the [Authorize] attribute to the MVCProductsController class. This will stop the unauthenticated users from accessing the MVCProductsController.
When we apply the Authorize class, all the action methods of that controller automatically inherit it. The Authorize attribute lives in the namespace Microsoft.AspNetCore.Authorization;
[Authorize]
public class MVCProductsController : Controller
{Now, when you navigate to /MVCProducts page, you are redirected to /Identity/Account/Login?ReturnUrl=%2FMVCProducts page.
Note that the MVCProducts is passed as the ReturnUrl to the login page. Once you are completed the login you are redirected back to the login page.
Now, what if we allow unauthenticated users to view the Product List & Details page, but restrict Create & Edit Page.
AllowAnonymous Attribute
AllowAnonymous attribute overrides Authorize attribute and allows access to unauthenticated users.
Appy the AllowAnonymous attribute on the Index action method. Now you can navigate to the Products page. But you cannot navigate to Products/Create page.
[Authorize]
public class MVCProductsController : Controller
{
private readonly ApplicationDbContext _context;
public MVCProductsController(ApplicationDbContext context)
{
_context = context;
}
// GET: MVCProducts
[AllowAnonymous]
public async Task<IActionResult> Index()
{
var applicationDbContext = _context.Products.Include(p => p.User);
return View(await applicationDbContext.ToListAsync());
}AllowAnonymous overrides everything.
If we apply the AllowAnonymous controller class access to all the methods are allowed, even if you decorate the action methods with Authorize attribute.
In the following example, access to the /Products is still allowed although we have an Authorize attribute on it. This is because the AllowAnonymous on the MVCProductsController overrides it.
[AllowAnonymous]
public class MVCProductsController : Controller
{
private readonly ApplicationDbContext _context;
public MVCProductsController(ApplicationDbContext context)
{
_context = context;
}
// GET: MVCProducts
[Authorize]
public async Task<IActionResult> Index()
{
var applicationDbContext = _context.Products.Include(p => p.User);
return View(await applicationDbContext.ToListAsync());
}If you apply both AllowAnonymous and Authorize attribute, then Authorize is ignored.
Securing a Razor Page
Apply Authorize attribute to the Page Model.
[Authorize]
public class CreateModel : PageModel
{
private readonly AuthzExample.Data.ApplicationDbContext _context;
public CreateModel(AuthzExample.Data.ApplicationDbContext context)
{
_context = context;
}
public IActionResult OnGet()
{
ViewData["userId"] = new SelectList(_context.Users, "Id", "Id");
return Page();
}
[BindProperty]
public Product Product { get; set; }
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Products.Add(Product);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}We cannot apply the Authorize attribute to Razor Page handlers.
For Example, in the code above, we have OnGet & OnPost page handlers. We cannot use Authorize attribute on them.
In case, you want to apply attributes on Razor Page Handlers, then Create a separate page for each page handler
To secure our, we need to Add Authorize attribute to every controller and page. But it time-consuming and error-prone as It is easier to miss a controller or page.
Fortunately, we can apply authorization globally using the RequireAuthorization extension method. We apply this method while configuring the end points.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
).RequireAuthorization();
endpoints.MapRazorPages().RequireAuthorization();
});Note, that this will apply the Authorize attribute on all the pages and controllers. Hence you need to add the AllowAnonymous attribute to those publically accessible pages. For Example, login, home & register pages.
[AllowAnonymous]
public class HomeController : Controller
{Login & Register pages come from the identity API and already has the AllowAnonymous attribute.
If you are using Razor pages, you can also make use of the Authorization Conventions to set the Authorize or AllowAnonymous attributes.
The support for Razor Pages comes from the AddRazorPages extenton method in the ConfigureServices method. We can pass addtional options to configure the Razor pages in the method.
By using the AuthorizePage, AuthorizeFolder, AllowAnonymousToPage, AllowAnonymousToFolder ,AuthorizeAreaPage & AuthorizeAreaFolder options, we can add the Authorize or AllowAnonymous attributes to the pages.
services.AddRazorPages(options =>
{
options.Conventions.AuthorizePage("/Contact");
options.Conventions.AuthorizeFolder("/Private");
options.Conventions.AllowAnonymousToPage("/Private/PublicPage");
options.Conventions.AllowAnonymousToFolder("/Private/PublicPages");
});Applying the method names that ends with Folder (ex: AuthorizeFolder or AuthorizeAreaFolder) will apply the attribute to all the pages under the folder. While method names that end with Page will apply the attribute to only that page.
Reference
Read More
- ASP.NET Core Tutorial
- Authentication in ASP.NET Core
- Cookie Authentication in ASP.NET Core
- Introduction to ASP.NET Core Identity
- ASP.NET Core Identity Tutorial From Scratch
- Sending Email Confirmation in ASP.NET Core
- Add Custom Fields to the user in ASP.NET Core Identity
- Change Primary key in ASP.NET Core Identity
- JWT Authentication in ASP.NET Core
- Introduction to Authorization
- Simple Authorization using Authorize attribute
- Adding & Managing Claims in ASP.NET Core Identity
- Claim Based Authorization in ASP.NET Core
- Policy-based Authorization
- Resource-Based Authorization


