razor-pagesasp.net-roles

Razor pages assign roles to users


I am wondering how to create and assign roles in Razor Pages 2.1. application.

I have found how to make them for MVC application (How to create roles in asp.net core and assign them to users and http://hishambinateya.com/role-based-authorization-in-razor-pages), however it does not work for razor pages as I have no IServicesProvider instance.

What I want is just to create admin role and assign it to seeded administrator account. Something similar has been done in this tutorial https://learn.microsoft.com/en-us/aspnet/core/security/authorization/secure-data?view=aspnetcore-2.1, but it seems be sutied for MVC and does not work properly after I applied it to my application. Please help me to understand how to create and seed roles in Razor Pages.

Will be very greatfull for help!


Solution

  • I handle the task next way. First, I used code proposed by Paul Madson in How to create roles in asp.net core and assign them to users. Abovementioned method I have inserted into Startup.cs. It creates administrator role and assigned it to seeded user.

        private void CreateRoles(IServiceProvider serviceProvider)
        {
            var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
            var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
            Task<IdentityResult> roleResult;
            string email = "someone@somewhere.com";
    
            //Check that there is an Administrator role and create if not
            Task<bool> hasAdminRole = roleManager.RoleExistsAsync("Administrator");
            hasAdminRole.Wait();
    
            if (!hasAdminRole.Result)
            {
                roleResult = roleManager.CreateAsync(new IdentityRole("Administrator"));
                roleResult.Wait();
            }
    
            //Check if the admin user exists and create it if not
            //Add to the Administrator role
    
            Task<ApplicationUser> testUser = userManager.FindByEmailAsync(email);
            testUser.Wait();
    
            if (testUser.Result == null)
            {
                ApplicationUser administrator = new ApplicationUser
                {
                Email = email,
                UserName = email,
                Name = email
                };
    
                Task<IdentityResult> newUser = userManager.CreateAsync(administrator, "_AStrongP@ssword!123");
                newUser.Wait();
    
                if (newUser.Result.Succeeded)
                {
                    Task<IdentityResult> newUserRole = userManager.AddToRoleAsync(administrator, "Administrator");
                    newUserRole.Wait();
                }
            }
    
        }
    

    Then, in the same file in Configure method I add argument (IServiceProvider serviceProvider), so you should have something like Configure(..., IServiceProvider serviceProvider). In the end of Configure method I add

    CreateRoles(serviceProvider).
    

    To make this code work create ApplicationUser class somwhere, for example in Data folder:

    using Microsoft.AspNetCore.Identity;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Sobopedia.Data
    {
        public class ApplicationUser: IdentityUser
        {
            public string Name { get; set; }
        }
    }
    

    Finally, inside ConfigureServices method substitute

    services.AddIdentity<ApplicationUser>()
                .AddEntityFrameworkStores<SobopediaContext>()
                .AddDefaultTokenProviders();
    

    with

    services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<SobopediaContext>()
                .AddDefaultTokenProviders();
    

    As a result, after programm starts in table AspNetRoles you will get a new role, while in table AspNetUsers you will have a new user acuiering administrator role.

    Unfortunatelly, after you add the following code

    services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<SobopediaContext>()
                .AddDefaultTokenProviders();
    

    pages Login and Registration stop working. In order to handle this problem you may follow next steps:

    1. Scaffold Identity following (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.1&tabs=visual-studio).

    2. Then substitute IdentityUser for ApplicationUser in entire solution. Preserv only IdentityUser inheritance in ApplicationUser class.

    3. Remove from Areas/identity/Pages/Account/Register.cs all things related to EmailSernder if you have no its implementation.

    In order to check correctness of the roles system you may do as follows. In the end of ConfigureServices method in Startup.cs add this code:

     services.AddAuthorization(options =>
                {
                    options.AddPolicy("RequireAdministratorRole", policy => policy.RequireRole("Administrator"));
                });
    
        services.AddMvc().AddRazorPagesOptions(options =>
                    {
    options.Conventions.AuthorizeFolder("/Contact","RequireAdministratorRole");
                    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    

    If it does not worki then just add [Authorize(Roles = "Administrator")] to Contact Page model, so it will look something like this:

    namespace Sobopedia.Pages
    {
        [Authorize(Roles = "Administrator")]
        public class ContactModel : PageModel
        {
            public string Message { get; set; }
    
            public void OnGet()
            {
                Message = "Your contact page.";
            }
        }
    }
    

    Now, in order to open Contact page you should be logged in with login someone@somewhere.com and password _AStrongP@ssword!123.