How to turn on Roles in Asp.net Identity 3.0 and MVC 6?

假如想象 提交于 2019-12-05 22:54:47

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"));

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));
                }
            }
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!