I will first introduce the steps that led me to role authorization problems.
First I add 2 roles in my construstor in HomeController.cs
public HomeController()
{
_db = new ApplicationDbContext();
_roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(_db));
_userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(_db));
List<string> roles = new List<string>()
{
"User", "Admin"
};
foreach(string role in roles)
{
if (!_roleManager.RoleExists(role))
{
_roleManager.Create(new IdentityRole(role));
}
}
}
The roles have been successfully added to the database.
Then I add role to new registered user in Register task in AccountController.cs
...
if (result.Succeeded)
{
await UserManager.AddToRoleAsync(user.Id, "User");
...
Role User
has been successfully assigned to new user (in table: AspNetUserRoles
)
Then if I change this user role to Admin
like this:
string userId = User.Identity.GetUserId<string>();
_userManager.RemoveFromRole(userId, "User");
_userManager.AddToRole(userId, "Admin");
And check it in my view (Razor) like this:
@if(User.IsInRole("Admin"))
{
<p> ok </p>
}
And check it in my HomeController via [Authorize(Roles = "Admin")]
.
Then it fails twice. if(User.IsInRole("Admin"))
return false and [Authorize(Roles = "Admin")]
also don't allow me to access method below it.
Moreover this new registered user has just User
role because [Authorize(Roles = "User")]
works and if(User.IsInRole("User"))
also return true.
What is weird is that IList<string> roles
:
string userId = User.Identity.GetUserId<string>();
IList<string> roles = _userManager.GetRoles(userId);
Actually correctly return new role list when new role is added via _userManager.AddToRole(userId, "Admin");
so user with default role User
has now just 1 role Admin
(because I remove previous role) which seems logic and it works.
If you know why my default role User
cannot be changed the way above post your answer, thanks.
To apply changes in user role replacement this user should sign in again.
Basically let's say we have some service called UserService
public class UserService
{
private ApplicationDbContext _db;
private ApplicationUserManager _userManager;
private ApplicationSignInManager _signInManager;
public UserService()
{
_db = new ApplicationDbContext();
_userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(_db));
IOwinContext owinContext = HttpContext.Current.GetOwinContext();
_signInManager = new ApplicationSignInManager(_userManager, owinContext.Authentication);
}
public async Task SaveRole()
{
ApplicationUser user = _userManager.FindById(HttpContext.Current.User.Identity.GetUserId());
await _signInManager.SignInAsync(user, true, true);
}
}
After assigning role to user we need to invoke SaveRole()
Task to update authentication cookie to be up to date with database.
public class HomeController : Controller
{
private UserService _userService;
public HomeController()
{
_userService = new UserService();
}
public async Task<ActionResult> ApplyRole()
{
await _userService.SaveRole();
return RedirectToAction("JustTestRole", "Home");
}
}
Now invoke ApplyRole
Task for example in view (.cshtml):
<li>@Html.ActionLink("Apply role", "ApplyRole", "Home")</li>
Current user role is applied and ready to test. For example:
[Authorize(Roles = "Admin")]
public ActionResult JustTestRole()
{
// to access this action user must have Admin role
}