0

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.

  • Did you try logged out then repeat login process for that user? Usually to set `User.IsInRole` immediately with new role assigned by `AddToRole[Async]`, you need to use `FindById()`, then `CreateIdentity()` with auth cookie and redo authentication process by `SignIn()`. – Tetsuya Yamamoto Dec 26 '18 at 03:59
  • Relogin works but I don't know how to deal with cookies so any link would be helpful. – Rafał Świerczek Dec 26 '18 at 09:44
  • Well, since logging out then redo login working fine, what you should do is re-authenticate the user immediately after using `AddToRole` to enforce new role so that `User.IsInRole` returns true for next request. The re-auth process should update auth cookie (which contains current user and role). – Tetsuya Yamamoto Dec 26 '18 at 09:50
  • I found this helpful answer https://stackoverflow.com/questions/29285406/refresh-current-users-role-when-changed-in-asp-net-identity-framework#answer-29286361. Basically, I do not have to update cookie manually because `SignIn` method do it for me. All I need to do is just use this method to relogin user so auth cookie will be up to date with database, right? I don't know how to use second parameter in ApplicationSignInManager constructor to create it's object to use `SignIn` method – Rafał Świerczek Dec 26 '18 at 11:39

1 Answers1

0

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
}