4

I am not sure if I am missing something here. By Default User.IsInRole() does not work even if user DOES HAVE some roles.

I don't have my own implementation of role stores. I am assuming that the default ones should work. Is there something special that I need to do in the Startup.cs to get the roles working? I'm using mvc 6 beta 2 default template.

Hao Kung
  • 28,040
  • 6
  • 84
  • 93
eadam
  • 23,151
  • 18
  • 48
  • 71

2 Answers2

3

The User.IsInRole() does not work if I add a role like this:

await UserManager.AddToRoleAsync(user, "Admin");

But it does work if I do this:

await UserManager.AddClaimAsync(user, claim: new Claim(ClaimTypes.Role.ToString(), "Admin"));

eadam
  • 23,151
  • 18
  • 48
  • 71
0

It looks like you're using Asp.NET Identity with the latest ASP.NET 5 stuff. I'm using the same (currently using RC1). I had a similar issue, and after some digging I found a solution by using SignInManager's RefreshSignInAsync() method.

Note that to get a hold of an instance of UserManager and SignInManager I use dependency injection, so the constructor for my controller looks like this:

public MyController(
    UserManager<ApplicationUser> userManager,
    SignInManager<ApplicationUser> signInManager)
{
    _userManager = userManager;
    _signInManager = signInManager;
}

My requirement was that if a particular controller method was accessed by an authenticated user, then a role would be added to that user if the user didn't already have that role, and it needed to take effect immediately. (Subsequent calls to User.IsInRole("TheRole") in controllers and views need return true without the user having to log out and back in).

Here's the action:

    [AllowAnonymous]
    public async Task<IActionResult> CreateProfile()
    {
        if (User == null || User.Identity == null || !User.Identity.IsAuthenticated)
        {
            return RedirectToAction("RegisterOrSignIn", "Account");
        }
        else
        {
            if (!User.IsInRole("TheRole"))
            {
                ApplicationUser applicationUser =
                    await _userManager.FindByIdAsync(User.GetUserId());
                await _userManager.AddToRoleAsync(applicationUser, "TheRole");
                await _signInManager.RefreshSignInAsync(applicationUser);
            }
            return RedirectToAction("Index");
        }
    }

Note you need

using System.Security.Claims;

for the GetUserId() extension method.

So the big things that I learned was to use UserManager's AddToRoleAsync and SignInManager's RefreshSignInAsync. The first adds a row to the AspNetUserRoles table. The second refreshes the cookie that, with the next request from the browser, will show that the user is in the role.

As an aside, I added a method called EnsureRoles() to Startup.cs. I call it right after the call to app.UseIdentity() in Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory). So, here's a snipit from Configure():

    ...

    // Add cookie-based authentication to the request pipeline.
    app.UseIdentity();

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
    // Ensure roles are in DB - OK not to await this for now
    EnsureRoles(app, loggerFactory);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

    ...

and here is EnsureRoles():

private async Task EnsureRoles(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
    ILogger logger = loggerFactory.CreateLogger<Startup>();
    RoleManager<IdentityRole> roleManager = app.ApplicationServices.GetService<RoleManager<IdentityRole>>();

    string[] roleNames = { "TheRole", "AnotherRole" };

    foreach (string roleName in roleNames)
    {
        bool roleExists = await roleManager.RoleExistsAsync(roleName);
        if (!roleExists)
        {
            logger.LogInformation(String.Format("!roleExists for roleName {0}", roleName));
            IdentityRole identityRole = new IdentityRole(roleName);
            IdentityResult identityResult = await roleManager.CreateAsync(identityRole);
            if (!identityResult.Succeeded)
            {
                logger.LogCritical(
                    String.Format(
                        "!identityResult.Succeeded after 
                         roleManager.CreateAsync(identityRole) for 
                         identityRole with roleName {0}",
                        roleName));
                foreach (var error in identityResult.Errors)
                {
                    logger.LogCritical(
                        String.Format(
                            "identityResult.Error.Description: {0}", 
                            error.Description));
                    logger.LogCritical(
                        String.Format(
                            "identityResult.Error.Code: {0}", 
                         error.Code));
                }
            }
        }
    }
}