Reputation: 135
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.
Upvotes: 0
Views: 2302
Reputation: 135
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
}
Upvotes: 0