How to create roles in ASP.NET Core and assign them to users?
My comment was deleted because I provided a link to a similar question I answered here. Ergo, I'll answer it more descriptively this time. Here goes.
You could do this easily by creating a CreateRoles
method in your startup
class. This helps check if the roles are created, and creates the roles if they aren't; on application startup. Like so.
private async Task CreateRoles(IServiceProvider serviceProvider) { //initializing custom roles var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>(); var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>(); string[] roleNames = { "Admin", "Manager", "Member" }; IdentityResult roleResult; foreach (var roleName in roleNames) { var roleExist = await RoleManager.RoleExistsAsync(roleName); if (!roleExist) { //create the roles and seed them to the database: Question 1 roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName)); } } //Here you could create a super user who will maintain the web app var poweruser = new ApplicationUser { UserName = Configuration["AppSettings:UserName"], Email = Configuration["AppSettings:UserEmail"], }; //Ensure you have these values in your appsettings.json file string userPWD = Configuration["AppSettings:UserPassword"]; var _user = await UserManager.FindByEmailAsync(Configuration["AppSettings:AdminUserEmail"]); if(_user == null) { var createPowerUser = await UserManager.CreateAsync(poweruser, userPWD); if (createPowerUser.Succeeded) { //here we tie the new user to the role await UserManager.AddToRoleAsync(poweruser, "Admin"); } } }
and then you could call the CreateRoles(serviceProvider).Wait();
method from the Configure
method in the Startup class. ensure you have IServiceProvider
as a parameter in the Configure
class.
Using role-based authorization in a controller to filter user access: Question 2
You can do this easily, like so.
[Authorize(Roles="Manager")]public class ManageController : Controller{ //....}
You can also use role-based authorization in the action method like so. Assign multiple roles, if you will
[Authorize(Roles="Admin, Manager")]public IActionResult Index(){/* ..... */ }
While this works fine, for a much better practice, you might want to read about using policy based role checks. You can find it on the ASP.NET core documentation here, or this article I wrote about it here
I have created an action in the Accounts
controller that calls a function to create the roles and assign the Admin
role to the default user. (You should probably remove the default user in production):
private async Task CreateRolesandUsers() { bool x = await _roleManager.RoleExistsAsync("Admin"); if (!x) { // first we create Admin rool var role = new IdentityRole(); role.Name = "Admin"; await _roleManager.CreateAsync(role); //Here we create a Admin super user who will maintain the website var user = new ApplicationUser(); user.UserName = "default"; user.Email = "default@default.com"; string userPWD = "somepassword"; IdentityResult chkUser = await _userManager.CreateAsync(user, userPWD); //Add default User to Role Admin if (chkUser.Succeeded) { var result1 = await _userManager.AddToRoleAsync(user, "Admin"); } } // creating Creating Manager role x = await _roleManager.RoleExistsAsync("Manager"); if (!x) { var role = new IdentityRole(); role.Name = "Manager"; await _roleManager.CreateAsync(role); } // creating Creating Employee role x = await _roleManager.RoleExistsAsync("Employee"); if (!x) { var role = new IdentityRole(); role.Name = "Employee"; await _roleManager.CreateAsync(role); } }
After you could create a controller to manage roles for the users.
Temi's answer is nearly correct, but you cannot call an asynchronous function from a non asynchronous function like he is suggesting. What you need to do is make asynchronous calls in a synchronous function like so :
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseDatabaseErrorPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseIdentity(); // Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715 app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); CreateRoles(serviceProvider); } 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(); administrator.Email = email; administrator.UserName = email; Task<IdentityResult> newUser = userManager.CreateAsync(administrator, "_AStrongP@ssword!"); newUser.Wait(); if (newUser.Result.Succeeded) { Task<IdentityResult> newUserRole = userManager.AddToRoleAsync(administrator, "Administrator"); newUserRole.Wait(); } } }
The key to this is the use of the Task<> class and forcing the system to wait in a slightly different way in a synchronous way.