ASP.NET Core Identity 2: User.IsInRole always returns false










1















The question: I call RoleManager.CreateAsync() and RoleManager.AddClaimAsync() to create roles and associated role claims. Then I call UserManager.AddToRoleAsync() to add users to those roles. But when the user logs in, neither the roles nor the associated claims show up in the ClaimsPrincipal (i.e. the Controller's User object). The upshot of this is that User.IsInRole() always returns false, and the collection of Claims returned by User.Claims doesn't contain the role claims, and the [Authorize(policy: xxx)] annotations don't work.



I should also add that one solution is to revert from using the new services.AddDefaultIdentity() (which is provided by the templated code) back to calling services.AddIdentity().AddSomething().AddSomethingElse(). I don't want to go there, because I've seen too many conflicting stories online about what I need to do to configure AddIdentity for various use cases. AddDefaultIdentity seems to do most things correctly without a lot of added fluent configuration.



BTW, I'm asking this question with the intention of answering it... unless someone else gives me a better answer than the one I'm prepared to post. I'm also asking this question because after several weeks of searching I have yet to find a good end-to-end example of creating and using Roles and Claims in ASP.NET Core Identity 2. Hopefully, the code example in this question might help someone else who stumbles upon it...



The setup:
I created a new ASP.NET Core Web Application, select Web Application (Model-View-Controller), and change the Authentication to Individual User Accounts. In the resultant project, I do the following:




  • In Package Manager Console, update the database to match the scaffolded migration:




    update-database





  • Add an ApplicationUser class that extends IdentityUser. This involves adding the class, adding a line of code to the ApplicationDbContext and replacing every instance of <IdentityUser> with <ApplicationUser> everywhere in the project.



    The new ApplicationUser class:



    public class ApplicationUser : IdentityUser

    public string FullName get; set;



    The updated ApplicationDbContext class:



    public class ApplicationDbContext : IdentityDbContext

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options)


    // Add this line of code
    public DbSet<ApplicationUser> ApplicationUsers get; set;




  • In Package Manager Console, create a new migration and update the database to incorporate the ApplicationUsers entity.




    add-migration m_001

    update-database





  • Add the following line of code in Startup.cs to enable RoleManager



    services.AddDefaultIdentity<ApplicationUser>()
    .AddRoles<IdentityRole>() // <-- Add this line
    .AddEntityFrameworkStores<ApplicationDbContext>();



  • Add some code to seed roles, claims, and users. The basic concept for this sample code is that I have two claims: can_report allows the holder to create reports, and can_test allows the holder to run tests. I have two Roles, Admin and Tester. The Tester role can run tests, but can't create reports. The Admin role can do both. So, I add the claims to the roles, and create one Admin test user and one Tester test user.



    First, I add a class whose sole purpose in life is to contain constants used elsewhere in this example:



    // Contains constant strings used throughout this example
    public class MyApp

    // Claims
    public const string CanTestClaim = "can_test";
    public const string CanReportClaim = "can_report";

    // Role names
    public const string AdminRole = "admin";
    public const string TesterRole = "tester";

    // Authorization policy names
    public const string CanTestPolicy = "can_test";
    public const string CanReportPolicy = "can_report";



    Next, I seed my roles, claims, and users. I put this code in the main landing page controller just for expedience; it really belongs in the "startup" Configure method, but that's an extra half-dozen lines of code...



    public class HomeController : Controller

    const string Password = "QwertyA1?";

    const string AdminEmail = "admin@example.com";
    const string TesterEmail = "tester@example.com";

    private readonly RoleManager<IdentityRole> _roleManager;
    private readonly UserManager<ApplicationUser> _userManager;

    // Constructor (DI claptrap)
    public HomeController(RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager)

    _roleManager = roleManager;
    _userManager = userManager;


    public async Task<IActionResult> Index()

    // Initialize roles
    if (!await _roleManager.RoleExistsAsync(MyApp.AdminRole))
    var role = new IdentityRole(MyApp.AdminRole);
    await _roleManager.CreateAsync(role);
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanTestClaim, ""));
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanReportClaim, ""));


    if (!await _roleManager.RoleExistsAsync(MyApp.TesterRole))
    var role = new IdentityRole(MyApp.TesterRole);
    await _roleManager.CreateAsync(role);
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanTestClaim, ""));


    // Initialize users
    var qry = _userManager.Users;
    IdentityResult result;

    if (await qry.Where(x => x.UserName == AdminEmail).FirstOrDefaultAsync() == null)
    var user = new ApplicationUser
    UserName = AdminEmail,
    Email = AdminEmail,
    FullName = "Administrator"
    ;

    result = await _userManager.CreateAsync(user, Password);
    if (!result.Succeeded) throw new InvalidOperationException(string.Join("

    if (await qry.Where(x => x.UserName == TesterEmail).FirstOrDefaultAsync() == null) ", result.Errors.Select(x => x.Description)));


    // Roles and Claims are in a cookie. Don't expect to see them in
    // the same request that creates them (i.e., the request that
    // executes the above code to create them). You need to refresh
    // the page to create a round-trip that includes the cookie.
    var admin = User.IsInRole(MyApp.AdminRole);
    var claims = User.Claims.ToList();

    return View();


    [Authorize(policy: MyApp.CanTestPolicy)]
    public IActionResult Test()

    return View();


    [Authorize(policy: MyApp.CanReportPolicy)]
    public IActionResult Report()

    return View();


    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()

    return View(new ErrorViewModel RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier );




    and I register my authentication policies in the "Startup" ConfigureServices routine, just after the call to services.AddMvc



     // Register authorization policies
    services.AddAuthorization(options =>
    options.AddPolicy(MyApp.CanTestPolicy, policy => policy.RequireClaim(MyApp.CanTestClaim));
    options.AddPolicy(MyApp.CanReportPolicy, policy => policy.RequireClaim(MyApp.CanReportClaim));
    );


Whew. Now, (assuming I've noted all of the applicable code I've added to the project, above), when I run the app, I notice that neither of my "built-in" test users can access either the /home/Test or /home/Report page. Moreover, if I set a breakpoint in the Index method, I see that my roles and claims do not exist in the User object. But I can look at the database and see all of the roles and claims are there.










share|improve this question
























  • How is the user authenticating? None of your code indicates how the app could possibly know who the current user is.

    – Brad
    Nov 13 '18 at 0:00











  • The user logs in. That is part of the code I get from the template.

    – Bob.at.Indigo.Health
    Nov 13 '18 at 2:11











  • Is there a claim containing the user id?

    – Brad
    Nov 13 '18 at 2:58











  • When a user logs in, the User.Claims list contains nameidentifier (a GUID with punctuation [dashes]), name (the username), and SecurityStamp (a GUID without punctuation). But, because I've associated a Role with the user, and the role has associated claims, I should also see those claims in the collection. (You'll have to wait for the answer to find out why my custom claims aren't there. ;)

    – Bob.at.Indigo.Health
    Nov 13 '18 at 4:23











  • Did u try adding custom claims

    – t-prisar
    Nov 13 '18 at 4:38















1















The question: I call RoleManager.CreateAsync() and RoleManager.AddClaimAsync() to create roles and associated role claims. Then I call UserManager.AddToRoleAsync() to add users to those roles. But when the user logs in, neither the roles nor the associated claims show up in the ClaimsPrincipal (i.e. the Controller's User object). The upshot of this is that User.IsInRole() always returns false, and the collection of Claims returned by User.Claims doesn't contain the role claims, and the [Authorize(policy: xxx)] annotations don't work.



I should also add that one solution is to revert from using the new services.AddDefaultIdentity() (which is provided by the templated code) back to calling services.AddIdentity().AddSomething().AddSomethingElse(). I don't want to go there, because I've seen too many conflicting stories online about what I need to do to configure AddIdentity for various use cases. AddDefaultIdentity seems to do most things correctly without a lot of added fluent configuration.



BTW, I'm asking this question with the intention of answering it... unless someone else gives me a better answer than the one I'm prepared to post. I'm also asking this question because after several weeks of searching I have yet to find a good end-to-end example of creating and using Roles and Claims in ASP.NET Core Identity 2. Hopefully, the code example in this question might help someone else who stumbles upon it...



The setup:
I created a new ASP.NET Core Web Application, select Web Application (Model-View-Controller), and change the Authentication to Individual User Accounts. In the resultant project, I do the following:




  • In Package Manager Console, update the database to match the scaffolded migration:




    update-database





  • Add an ApplicationUser class that extends IdentityUser. This involves adding the class, adding a line of code to the ApplicationDbContext and replacing every instance of <IdentityUser> with <ApplicationUser> everywhere in the project.



    The new ApplicationUser class:



    public class ApplicationUser : IdentityUser

    public string FullName get; set;



    The updated ApplicationDbContext class:



    public class ApplicationDbContext : IdentityDbContext

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options)


    // Add this line of code
    public DbSet<ApplicationUser> ApplicationUsers get; set;




  • In Package Manager Console, create a new migration and update the database to incorporate the ApplicationUsers entity.




    add-migration m_001

    update-database





  • Add the following line of code in Startup.cs to enable RoleManager



    services.AddDefaultIdentity<ApplicationUser>()
    .AddRoles<IdentityRole>() // <-- Add this line
    .AddEntityFrameworkStores<ApplicationDbContext>();



  • Add some code to seed roles, claims, and users. The basic concept for this sample code is that I have two claims: can_report allows the holder to create reports, and can_test allows the holder to run tests. I have two Roles, Admin and Tester. The Tester role can run tests, but can't create reports. The Admin role can do both. So, I add the claims to the roles, and create one Admin test user and one Tester test user.



    First, I add a class whose sole purpose in life is to contain constants used elsewhere in this example:



    // Contains constant strings used throughout this example
    public class MyApp

    // Claims
    public const string CanTestClaim = "can_test";
    public const string CanReportClaim = "can_report";

    // Role names
    public const string AdminRole = "admin";
    public const string TesterRole = "tester";

    // Authorization policy names
    public const string CanTestPolicy = "can_test";
    public const string CanReportPolicy = "can_report";



    Next, I seed my roles, claims, and users. I put this code in the main landing page controller just for expedience; it really belongs in the "startup" Configure method, but that's an extra half-dozen lines of code...



    public class HomeController : Controller

    const string Password = "QwertyA1?";

    const string AdminEmail = "admin@example.com";
    const string TesterEmail = "tester@example.com";

    private readonly RoleManager<IdentityRole> _roleManager;
    private readonly UserManager<ApplicationUser> _userManager;

    // Constructor (DI claptrap)
    public HomeController(RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager)

    _roleManager = roleManager;
    _userManager = userManager;


    public async Task<IActionResult> Index()

    // Initialize roles
    if (!await _roleManager.RoleExistsAsync(MyApp.AdminRole))
    var role = new IdentityRole(MyApp.AdminRole);
    await _roleManager.CreateAsync(role);
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanTestClaim, ""));
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanReportClaim, ""));


    if (!await _roleManager.RoleExistsAsync(MyApp.TesterRole))
    var role = new IdentityRole(MyApp.TesterRole);
    await _roleManager.CreateAsync(role);
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanTestClaim, ""));


    // Initialize users
    var qry = _userManager.Users;
    IdentityResult result;

    if (await qry.Where(x => x.UserName == AdminEmail).FirstOrDefaultAsync() == null)
    var user = new ApplicationUser
    UserName = AdminEmail,
    Email = AdminEmail,
    FullName = "Administrator"
    ;

    result = await _userManager.CreateAsync(user, Password);
    if (!result.Succeeded) throw new InvalidOperationException(string.Join("

    if (await qry.Where(x => x.UserName == TesterEmail).FirstOrDefaultAsync() == null) ", result.Errors.Select(x => x.Description)));


    // Roles and Claims are in a cookie. Don't expect to see them in
    // the same request that creates them (i.e., the request that
    // executes the above code to create them). You need to refresh
    // the page to create a round-trip that includes the cookie.
    var admin = User.IsInRole(MyApp.AdminRole);
    var claims = User.Claims.ToList();

    return View();


    [Authorize(policy: MyApp.CanTestPolicy)]
    public IActionResult Test()

    return View();


    [Authorize(policy: MyApp.CanReportPolicy)]
    public IActionResult Report()

    return View();


    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()

    return View(new ErrorViewModel RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier );




    and I register my authentication policies in the "Startup" ConfigureServices routine, just after the call to services.AddMvc



     // Register authorization policies
    services.AddAuthorization(options =>
    options.AddPolicy(MyApp.CanTestPolicy, policy => policy.RequireClaim(MyApp.CanTestClaim));
    options.AddPolicy(MyApp.CanReportPolicy, policy => policy.RequireClaim(MyApp.CanReportClaim));
    );


Whew. Now, (assuming I've noted all of the applicable code I've added to the project, above), when I run the app, I notice that neither of my "built-in" test users can access either the /home/Test or /home/Report page. Moreover, if I set a breakpoint in the Index method, I see that my roles and claims do not exist in the User object. But I can look at the database and see all of the roles and claims are there.










share|improve this question
























  • How is the user authenticating? None of your code indicates how the app could possibly know who the current user is.

    – Brad
    Nov 13 '18 at 0:00











  • The user logs in. That is part of the code I get from the template.

    – Bob.at.Indigo.Health
    Nov 13 '18 at 2:11











  • Is there a claim containing the user id?

    – Brad
    Nov 13 '18 at 2:58











  • When a user logs in, the User.Claims list contains nameidentifier (a GUID with punctuation [dashes]), name (the username), and SecurityStamp (a GUID without punctuation). But, because I've associated a Role with the user, and the role has associated claims, I should also see those claims in the collection. (You'll have to wait for the answer to find out why my custom claims aren't there. ;)

    – Bob.at.Indigo.Health
    Nov 13 '18 at 4:23











  • Did u try adding custom claims

    – t-prisar
    Nov 13 '18 at 4:38













1












1








1


1






The question: I call RoleManager.CreateAsync() and RoleManager.AddClaimAsync() to create roles and associated role claims. Then I call UserManager.AddToRoleAsync() to add users to those roles. But when the user logs in, neither the roles nor the associated claims show up in the ClaimsPrincipal (i.e. the Controller's User object). The upshot of this is that User.IsInRole() always returns false, and the collection of Claims returned by User.Claims doesn't contain the role claims, and the [Authorize(policy: xxx)] annotations don't work.



I should also add that one solution is to revert from using the new services.AddDefaultIdentity() (which is provided by the templated code) back to calling services.AddIdentity().AddSomething().AddSomethingElse(). I don't want to go there, because I've seen too many conflicting stories online about what I need to do to configure AddIdentity for various use cases. AddDefaultIdentity seems to do most things correctly without a lot of added fluent configuration.



BTW, I'm asking this question with the intention of answering it... unless someone else gives me a better answer than the one I'm prepared to post. I'm also asking this question because after several weeks of searching I have yet to find a good end-to-end example of creating and using Roles and Claims in ASP.NET Core Identity 2. Hopefully, the code example in this question might help someone else who stumbles upon it...



The setup:
I created a new ASP.NET Core Web Application, select Web Application (Model-View-Controller), and change the Authentication to Individual User Accounts. In the resultant project, I do the following:




  • In Package Manager Console, update the database to match the scaffolded migration:




    update-database





  • Add an ApplicationUser class that extends IdentityUser. This involves adding the class, adding a line of code to the ApplicationDbContext and replacing every instance of <IdentityUser> with <ApplicationUser> everywhere in the project.



    The new ApplicationUser class:



    public class ApplicationUser : IdentityUser

    public string FullName get; set;



    The updated ApplicationDbContext class:



    public class ApplicationDbContext : IdentityDbContext

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options)


    // Add this line of code
    public DbSet<ApplicationUser> ApplicationUsers get; set;




  • In Package Manager Console, create a new migration and update the database to incorporate the ApplicationUsers entity.




    add-migration m_001

    update-database





  • Add the following line of code in Startup.cs to enable RoleManager



    services.AddDefaultIdentity<ApplicationUser>()
    .AddRoles<IdentityRole>() // <-- Add this line
    .AddEntityFrameworkStores<ApplicationDbContext>();



  • Add some code to seed roles, claims, and users. The basic concept for this sample code is that I have two claims: can_report allows the holder to create reports, and can_test allows the holder to run tests. I have two Roles, Admin and Tester. The Tester role can run tests, but can't create reports. The Admin role can do both. So, I add the claims to the roles, and create one Admin test user and one Tester test user.



    First, I add a class whose sole purpose in life is to contain constants used elsewhere in this example:



    // Contains constant strings used throughout this example
    public class MyApp

    // Claims
    public const string CanTestClaim = "can_test";
    public const string CanReportClaim = "can_report";

    // Role names
    public const string AdminRole = "admin";
    public const string TesterRole = "tester";

    // Authorization policy names
    public const string CanTestPolicy = "can_test";
    public const string CanReportPolicy = "can_report";



    Next, I seed my roles, claims, and users. I put this code in the main landing page controller just for expedience; it really belongs in the "startup" Configure method, but that's an extra half-dozen lines of code...



    public class HomeController : Controller

    const string Password = "QwertyA1?";

    const string AdminEmail = "admin@example.com";
    const string TesterEmail = "tester@example.com";

    private readonly RoleManager<IdentityRole> _roleManager;
    private readonly UserManager<ApplicationUser> _userManager;

    // Constructor (DI claptrap)
    public HomeController(RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager)

    _roleManager = roleManager;
    _userManager = userManager;


    public async Task<IActionResult> Index()

    // Initialize roles
    if (!await _roleManager.RoleExistsAsync(MyApp.AdminRole))
    var role = new IdentityRole(MyApp.AdminRole);
    await _roleManager.CreateAsync(role);
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanTestClaim, ""));
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanReportClaim, ""));


    if (!await _roleManager.RoleExistsAsync(MyApp.TesterRole))
    var role = new IdentityRole(MyApp.TesterRole);
    await _roleManager.CreateAsync(role);
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanTestClaim, ""));


    // Initialize users
    var qry = _userManager.Users;
    IdentityResult result;

    if (await qry.Where(x => x.UserName == AdminEmail).FirstOrDefaultAsync() == null)
    var user = new ApplicationUser
    UserName = AdminEmail,
    Email = AdminEmail,
    FullName = "Administrator"
    ;

    result = await _userManager.CreateAsync(user, Password);
    if (!result.Succeeded) throw new InvalidOperationException(string.Join("

    if (await qry.Where(x => x.UserName == TesterEmail).FirstOrDefaultAsync() == null) ", result.Errors.Select(x => x.Description)));


    // Roles and Claims are in a cookie. Don't expect to see them in
    // the same request that creates them (i.e., the request that
    // executes the above code to create them). You need to refresh
    // the page to create a round-trip that includes the cookie.
    var admin = User.IsInRole(MyApp.AdminRole);
    var claims = User.Claims.ToList();

    return View();


    [Authorize(policy: MyApp.CanTestPolicy)]
    public IActionResult Test()

    return View();


    [Authorize(policy: MyApp.CanReportPolicy)]
    public IActionResult Report()

    return View();


    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()

    return View(new ErrorViewModel RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier );




    and I register my authentication policies in the "Startup" ConfigureServices routine, just after the call to services.AddMvc



     // Register authorization policies
    services.AddAuthorization(options =>
    options.AddPolicy(MyApp.CanTestPolicy, policy => policy.RequireClaim(MyApp.CanTestClaim));
    options.AddPolicy(MyApp.CanReportPolicy, policy => policy.RequireClaim(MyApp.CanReportClaim));
    );


Whew. Now, (assuming I've noted all of the applicable code I've added to the project, above), when I run the app, I notice that neither of my "built-in" test users can access either the /home/Test or /home/Report page. Moreover, if I set a breakpoint in the Index method, I see that my roles and claims do not exist in the User object. But I can look at the database and see all of the roles and claims are there.










share|improve this question
















The question: I call RoleManager.CreateAsync() and RoleManager.AddClaimAsync() to create roles and associated role claims. Then I call UserManager.AddToRoleAsync() to add users to those roles. But when the user logs in, neither the roles nor the associated claims show up in the ClaimsPrincipal (i.e. the Controller's User object). The upshot of this is that User.IsInRole() always returns false, and the collection of Claims returned by User.Claims doesn't contain the role claims, and the [Authorize(policy: xxx)] annotations don't work.



I should also add that one solution is to revert from using the new services.AddDefaultIdentity() (which is provided by the templated code) back to calling services.AddIdentity().AddSomething().AddSomethingElse(). I don't want to go there, because I've seen too many conflicting stories online about what I need to do to configure AddIdentity for various use cases. AddDefaultIdentity seems to do most things correctly without a lot of added fluent configuration.



BTW, I'm asking this question with the intention of answering it... unless someone else gives me a better answer than the one I'm prepared to post. I'm also asking this question because after several weeks of searching I have yet to find a good end-to-end example of creating and using Roles and Claims in ASP.NET Core Identity 2. Hopefully, the code example in this question might help someone else who stumbles upon it...



The setup:
I created a new ASP.NET Core Web Application, select Web Application (Model-View-Controller), and change the Authentication to Individual User Accounts. In the resultant project, I do the following:




  • In Package Manager Console, update the database to match the scaffolded migration:




    update-database





  • Add an ApplicationUser class that extends IdentityUser. This involves adding the class, adding a line of code to the ApplicationDbContext and replacing every instance of <IdentityUser> with <ApplicationUser> everywhere in the project.



    The new ApplicationUser class:



    public class ApplicationUser : IdentityUser

    public string FullName get; set;



    The updated ApplicationDbContext class:



    public class ApplicationDbContext : IdentityDbContext

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options)


    // Add this line of code
    public DbSet<ApplicationUser> ApplicationUsers get; set;




  • In Package Manager Console, create a new migration and update the database to incorporate the ApplicationUsers entity.




    add-migration m_001

    update-database





  • Add the following line of code in Startup.cs to enable RoleManager



    services.AddDefaultIdentity<ApplicationUser>()
    .AddRoles<IdentityRole>() // <-- Add this line
    .AddEntityFrameworkStores<ApplicationDbContext>();



  • Add some code to seed roles, claims, and users. The basic concept for this sample code is that I have two claims: can_report allows the holder to create reports, and can_test allows the holder to run tests. I have two Roles, Admin and Tester. The Tester role can run tests, but can't create reports. The Admin role can do both. So, I add the claims to the roles, and create one Admin test user and one Tester test user.



    First, I add a class whose sole purpose in life is to contain constants used elsewhere in this example:



    // Contains constant strings used throughout this example
    public class MyApp

    // Claims
    public const string CanTestClaim = "can_test";
    public const string CanReportClaim = "can_report";

    // Role names
    public const string AdminRole = "admin";
    public const string TesterRole = "tester";

    // Authorization policy names
    public const string CanTestPolicy = "can_test";
    public const string CanReportPolicy = "can_report";



    Next, I seed my roles, claims, and users. I put this code in the main landing page controller just for expedience; it really belongs in the "startup" Configure method, but that's an extra half-dozen lines of code...



    public class HomeController : Controller

    const string Password = "QwertyA1?";

    const string AdminEmail = "admin@example.com";
    const string TesterEmail = "tester@example.com";

    private readonly RoleManager<IdentityRole> _roleManager;
    private readonly UserManager<ApplicationUser> _userManager;

    // Constructor (DI claptrap)
    public HomeController(RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager)

    _roleManager = roleManager;
    _userManager = userManager;


    public async Task<IActionResult> Index()

    // Initialize roles
    if (!await _roleManager.RoleExistsAsync(MyApp.AdminRole))
    var role = new IdentityRole(MyApp.AdminRole);
    await _roleManager.CreateAsync(role);
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanTestClaim, ""));
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanReportClaim, ""));


    if (!await _roleManager.RoleExistsAsync(MyApp.TesterRole))
    var role = new IdentityRole(MyApp.TesterRole);
    await _roleManager.CreateAsync(role);
    await _roleManager.AddClaimAsync(role, new Claim(MyApp.CanTestClaim, ""));


    // Initialize users
    var qry = _userManager.Users;
    IdentityResult result;

    if (await qry.Where(x => x.UserName == AdminEmail).FirstOrDefaultAsync() == null)
    var user = new ApplicationUser
    UserName = AdminEmail,
    Email = AdminEmail,
    FullName = "Administrator"
    ;

    result = await _userManager.CreateAsync(user, Password);
    if (!result.Succeeded) throw new InvalidOperationException(string.Join("

    if (await qry.Where(x => x.UserName == TesterEmail).FirstOrDefaultAsync() == null) ", result.Errors.Select(x => x.Description)));


    // Roles and Claims are in a cookie. Don't expect to see them in
    // the same request that creates them (i.e., the request that
    // executes the above code to create them). You need to refresh
    // the page to create a round-trip that includes the cookie.
    var admin = User.IsInRole(MyApp.AdminRole);
    var claims = User.Claims.ToList();

    return View();


    [Authorize(policy: MyApp.CanTestPolicy)]
    public IActionResult Test()

    return View();


    [Authorize(policy: MyApp.CanReportPolicy)]
    public IActionResult Report()

    return View();


    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()

    return View(new ErrorViewModel RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier );




    and I register my authentication policies in the "Startup" ConfigureServices routine, just after the call to services.AddMvc



     // Register authorization policies
    services.AddAuthorization(options =>
    options.AddPolicy(MyApp.CanTestPolicy, policy => policy.RequireClaim(MyApp.CanTestClaim));
    options.AddPolicy(MyApp.CanReportPolicy, policy => policy.RequireClaim(MyApp.CanReportClaim));
    );


Whew. Now, (assuming I've noted all of the applicable code I've added to the project, above), when I run the app, I notice that neither of my "built-in" test users can access either the /home/Test or /home/Report page. Moreover, if I set a breakpoint in the Index method, I see that my roles and claims do not exist in the User object. But I can look at the database and see all of the roles and claims are there.







asp.net-core asp.net-core-mvc asp.net-identity






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 13 '18 at 20:07







Bob.at.Indigo.Health

















asked Nov 12 '18 at 23:17









Bob.at.Indigo.HealthBob.at.Indigo.Health

4,29184277




4,29184277












  • How is the user authenticating? None of your code indicates how the app could possibly know who the current user is.

    – Brad
    Nov 13 '18 at 0:00











  • The user logs in. That is part of the code I get from the template.

    – Bob.at.Indigo.Health
    Nov 13 '18 at 2:11











  • Is there a claim containing the user id?

    – Brad
    Nov 13 '18 at 2:58











  • When a user logs in, the User.Claims list contains nameidentifier (a GUID with punctuation [dashes]), name (the username), and SecurityStamp (a GUID without punctuation). But, because I've associated a Role with the user, and the role has associated claims, I should also see those claims in the collection. (You'll have to wait for the answer to find out why my custom claims aren't there. ;)

    – Bob.at.Indigo.Health
    Nov 13 '18 at 4:23











  • Did u try adding custom claims

    – t-prisar
    Nov 13 '18 at 4:38

















  • How is the user authenticating? None of your code indicates how the app could possibly know who the current user is.

    – Brad
    Nov 13 '18 at 0:00











  • The user logs in. That is part of the code I get from the template.

    – Bob.at.Indigo.Health
    Nov 13 '18 at 2:11











  • Is there a claim containing the user id?

    – Brad
    Nov 13 '18 at 2:58











  • When a user logs in, the User.Claims list contains nameidentifier (a GUID with punctuation [dashes]), name (the username), and SecurityStamp (a GUID without punctuation). But, because I've associated a Role with the user, and the role has associated claims, I should also see those claims in the collection. (You'll have to wait for the answer to find out why my custom claims aren't there. ;)

    – Bob.at.Indigo.Health
    Nov 13 '18 at 4:23











  • Did u try adding custom claims

    – t-prisar
    Nov 13 '18 at 4:38
















How is the user authenticating? None of your code indicates how the app could possibly know who the current user is.

– Brad
Nov 13 '18 at 0:00





How is the user authenticating? None of your code indicates how the app could possibly know who the current user is.

– Brad
Nov 13 '18 at 0:00













The user logs in. That is part of the code I get from the template.

– Bob.at.Indigo.Health
Nov 13 '18 at 2:11





The user logs in. That is part of the code I get from the template.

– Bob.at.Indigo.Health
Nov 13 '18 at 2:11













Is there a claim containing the user id?

– Brad
Nov 13 '18 at 2:58





Is there a claim containing the user id?

– Brad
Nov 13 '18 at 2:58













When a user logs in, the User.Claims list contains nameidentifier (a GUID with punctuation [dashes]), name (the username), and SecurityStamp (a GUID without punctuation). But, because I've associated a Role with the user, and the role has associated claims, I should also see those claims in the collection. (You'll have to wait for the answer to find out why my custom claims aren't there. ;)

– Bob.at.Indigo.Health
Nov 13 '18 at 4:23





When a user logs in, the User.Claims list contains nameidentifier (a GUID with punctuation [dashes]), name (the username), and SecurityStamp (a GUID without punctuation). But, because I've associated a Role with the user, and the role has associated claims, I should also see those claims in the collection. (You'll have to wait for the answer to find out why my custom claims aren't there. ;)

– Bob.at.Indigo.Health
Nov 13 '18 at 4:23













Did u try adding custom claims

– t-prisar
Nov 13 '18 at 4:38





Did u try adding custom claims

– t-prisar
Nov 13 '18 at 4:38












2 Answers
2






active

oldest

votes


















3














So, to recap, the question asks why the code provided by the ASP.NET Core Web Application template doesn't load roles or role claims into the cookie when a user logs in.



After much Googling and experimenting, there appear to be two modifications that must be made to the templated code in order to get Roles and Role Claims to work:



First, you must add the following line of code in Startup.cs to enable RoleManager. (This bit of magic was mentioned in the OP.)



services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<IdentityRole>() // <-- Add this line
.AddEntityFrameworkStores<ApplicationDbContext>();


But wait, there's more! According to this discussion on GitHub, getting the roles and claims to show up in the cookie involves either reverting to the service.AddIdentity initialization code, or sticking with service.AddDefaultIdentity and adding this line of code to ConfigureServices:



// Add Role claims to the User object
// See: https://github.com/aspnet/Identity/issues/1813#issuecomment-420066501
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();


If you read the discussion referenced above, you'll see that Roles and Role Claims are apparently kind-of-deprecated, or at least not eagerly supported. Personally, I find it really useful to assign claims to roles, assign roles to users, and then make authorization decisions based on the claims (which are granted to the users based on their roles). This gives me an easy, declarative way to allow, for example, one function to be accessed by multiple roles (i.e. all of the roles that contain the claim used to enable that function).



But you DO want to pay attention to the amount of role and claim data being carried in the auth cookie. More data means more bytes sent to the server with each request, and I have no clue what happens when you bump up against some sort of limit to the cookie size.






share|improve this answer
































    1














    Ahh, there are some changes from ASP.NET Core version 2.0 to 2.1. AddDefaultIdentity is the one.



    I don't know where to start from your code, so, I will provide an example to create and get user role(s).



    Let's create UserRoles first:



    public enum UserRoles

    [Display(Name = "Quản trị viên")]
    Administrator = 0,

    [Display(Name = "Kiểm soát viên")]
    Moderator = 1,

    [Display(Name = "Thành viên")]
    Member = 2



    Note: You can remove the attribute Display.



    Then, we create RolesExtensions class:



    public static class RolesExtensions

    public static async Task InitializeAsync(RoleManager<IdentityRole> roleManager)

    foreach (string roleName in Enum.GetNames(typeof(UserRoles)))

    if (!await roleManager.RoleExistsAsync(roleName))

    await roleManager.CreateAsync(new IdentityRole(roleName));






    Next, in the Startup.cs class, we run it:



     public void Configure(
    IApplicationBuilder app,
    IHostingEnvironment env,
    RoleManager<IdentityRole> roleManager)

    // other settings...

    app.UseMvc(routes =>

    routes.MapRoute(
    name: "default",
    template: "controller=Home/action=Index/id?");
    );

    var task = RolesExtensions.InitializeAsync(roleManager);
    task.Wait();



    Note: Configure requires a returned type void, so we need to create a task to initialize the user roles and we call Wait method.



    Do not change the returned type like this:



    public async void Configure(...)

    await RolesExtensions.InitializeAsync(roleManager);



    Source: Async/Await - Best Practices in Asynchronous Programming



    In the ConfigureServices method, these configurations would NOT work (we cannot use User.IsInRole correctly):



    services.AddDefaultIdentity<ApplicationUser>()
    //.AddRoles<IdentityRole>()
    //.AddRoleManager<RoleManager<IdentityRole>>()
    .AddEntityFrameworkStores<ApplicationDbContext>();


    I don't know why but AddRoles and AddRoleManager don't support to check role for a user (User.IsInRole).



    In this case, we need to register service like this:



    services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();


    By using this way, we create 3 user roles in the databse:



    1



    When register new user, we just need to call:



    await _userManager.AddToRoleAsync(user, nameof(UserRoles.Administrator));



    Finally, we can use [Authorize(Roles = "Administrator")] and:



    if (User.IsInRole("Administrator"))

    // authorized


    // or
    if (User.IsInRole(nameof(UserRoles.Administrator)))

    // authorized


    // but
    if (User.IsInRole("ADMINISTRATOR"))

    // authorized



    P/S: There are a lot things which need to be implement to achieve this goal. So maybe I missed something in this example.






    share|improve this answer























    • Hey Tan, great answer. I guess I should have added that I want to use the newfangled services.AddDefaultIdentity rather than services.AddIdentity()… because I've seen too many conflicting stories online about what fluent methods need to follow AddIdentity to get it to work for various use cases.

      – Bob.at.Indigo.Health
      Nov 13 '18 at 20:02











    • Also, I think that your call to InitializeAsync my be prone to deadlock issues in ASP.NET. Take a look at this SO answer. This issue of calling an async method from the synchronous Startup methods is why my example code put all of the seed logic into the Controller code (so I wouldn't have to include the extra code needed to do it correctly from the Startup code).

      – Bob.at.Indigo.Health
      Nov 13 '18 at 20:16











    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53271496%2fasp-net-core-identity-2-user-isinrole-always-returns-false%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3














    So, to recap, the question asks why the code provided by the ASP.NET Core Web Application template doesn't load roles or role claims into the cookie when a user logs in.



    After much Googling and experimenting, there appear to be two modifications that must be made to the templated code in order to get Roles and Role Claims to work:



    First, you must add the following line of code in Startup.cs to enable RoleManager. (This bit of magic was mentioned in the OP.)



    services.AddDefaultIdentity<ApplicationUser>()
    .AddRoles<IdentityRole>() // <-- Add this line
    .AddEntityFrameworkStores<ApplicationDbContext>();


    But wait, there's more! According to this discussion on GitHub, getting the roles and claims to show up in the cookie involves either reverting to the service.AddIdentity initialization code, or sticking with service.AddDefaultIdentity and adding this line of code to ConfigureServices:



    // Add Role claims to the User object
    // See: https://github.com/aspnet/Identity/issues/1813#issuecomment-420066501
    services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();


    If you read the discussion referenced above, you'll see that Roles and Role Claims are apparently kind-of-deprecated, or at least not eagerly supported. Personally, I find it really useful to assign claims to roles, assign roles to users, and then make authorization decisions based on the claims (which are granted to the users based on their roles). This gives me an easy, declarative way to allow, for example, one function to be accessed by multiple roles (i.e. all of the roles that contain the claim used to enable that function).



    But you DO want to pay attention to the amount of role and claim data being carried in the auth cookie. More data means more bytes sent to the server with each request, and I have no clue what happens when you bump up against some sort of limit to the cookie size.






    share|improve this answer





























      3














      So, to recap, the question asks why the code provided by the ASP.NET Core Web Application template doesn't load roles or role claims into the cookie when a user logs in.



      After much Googling and experimenting, there appear to be two modifications that must be made to the templated code in order to get Roles and Role Claims to work:



      First, you must add the following line of code in Startup.cs to enable RoleManager. (This bit of magic was mentioned in the OP.)



      services.AddDefaultIdentity<ApplicationUser>()
      .AddRoles<IdentityRole>() // <-- Add this line
      .AddEntityFrameworkStores<ApplicationDbContext>();


      But wait, there's more! According to this discussion on GitHub, getting the roles and claims to show up in the cookie involves either reverting to the service.AddIdentity initialization code, or sticking with service.AddDefaultIdentity and adding this line of code to ConfigureServices:



      // Add Role claims to the User object
      // See: https://github.com/aspnet/Identity/issues/1813#issuecomment-420066501
      services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();


      If you read the discussion referenced above, you'll see that Roles and Role Claims are apparently kind-of-deprecated, or at least not eagerly supported. Personally, I find it really useful to assign claims to roles, assign roles to users, and then make authorization decisions based on the claims (which are granted to the users based on their roles). This gives me an easy, declarative way to allow, for example, one function to be accessed by multiple roles (i.e. all of the roles that contain the claim used to enable that function).



      But you DO want to pay attention to the amount of role and claim data being carried in the auth cookie. More data means more bytes sent to the server with each request, and I have no clue what happens when you bump up against some sort of limit to the cookie size.






      share|improve this answer



























        3












        3








        3







        So, to recap, the question asks why the code provided by the ASP.NET Core Web Application template doesn't load roles or role claims into the cookie when a user logs in.



        After much Googling and experimenting, there appear to be two modifications that must be made to the templated code in order to get Roles and Role Claims to work:



        First, you must add the following line of code in Startup.cs to enable RoleManager. (This bit of magic was mentioned in the OP.)



        services.AddDefaultIdentity<ApplicationUser>()
        .AddRoles<IdentityRole>() // <-- Add this line
        .AddEntityFrameworkStores<ApplicationDbContext>();


        But wait, there's more! According to this discussion on GitHub, getting the roles and claims to show up in the cookie involves either reverting to the service.AddIdentity initialization code, or sticking with service.AddDefaultIdentity and adding this line of code to ConfigureServices:



        // Add Role claims to the User object
        // See: https://github.com/aspnet/Identity/issues/1813#issuecomment-420066501
        services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();


        If you read the discussion referenced above, you'll see that Roles and Role Claims are apparently kind-of-deprecated, or at least not eagerly supported. Personally, I find it really useful to assign claims to roles, assign roles to users, and then make authorization decisions based on the claims (which are granted to the users based on their roles). This gives me an easy, declarative way to allow, for example, one function to be accessed by multiple roles (i.e. all of the roles that contain the claim used to enable that function).



        But you DO want to pay attention to the amount of role and claim data being carried in the auth cookie. More data means more bytes sent to the server with each request, and I have no clue what happens when you bump up against some sort of limit to the cookie size.






        share|improve this answer















        So, to recap, the question asks why the code provided by the ASP.NET Core Web Application template doesn't load roles or role claims into the cookie when a user logs in.



        After much Googling and experimenting, there appear to be two modifications that must be made to the templated code in order to get Roles and Role Claims to work:



        First, you must add the following line of code in Startup.cs to enable RoleManager. (This bit of magic was mentioned in the OP.)



        services.AddDefaultIdentity<ApplicationUser>()
        .AddRoles<IdentityRole>() // <-- Add this line
        .AddEntityFrameworkStores<ApplicationDbContext>();


        But wait, there's more! According to this discussion on GitHub, getting the roles and claims to show up in the cookie involves either reverting to the service.AddIdentity initialization code, or sticking with service.AddDefaultIdentity and adding this line of code to ConfigureServices:



        // Add Role claims to the User object
        // See: https://github.com/aspnet/Identity/issues/1813#issuecomment-420066501
        services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();


        If you read the discussion referenced above, you'll see that Roles and Role Claims are apparently kind-of-deprecated, or at least not eagerly supported. Personally, I find it really useful to assign claims to roles, assign roles to users, and then make authorization decisions based on the claims (which are granted to the users based on their roles). This gives me an easy, declarative way to allow, for example, one function to be accessed by multiple roles (i.e. all of the roles that contain the claim used to enable that function).



        But you DO want to pay attention to the amount of role and claim data being carried in the auth cookie. More data means more bytes sent to the server with each request, and I have no clue what happens when you bump up against some sort of limit to the cookie size.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 16 '18 at 18:58

























        answered Nov 13 '18 at 20:36









        Bob.at.Indigo.HealthBob.at.Indigo.Health

        4,29184277




        4,29184277























            1














            Ahh, there are some changes from ASP.NET Core version 2.0 to 2.1. AddDefaultIdentity is the one.



            I don't know where to start from your code, so, I will provide an example to create and get user role(s).



            Let's create UserRoles first:



            public enum UserRoles

            [Display(Name = "Quản trị viên")]
            Administrator = 0,

            [Display(Name = "Kiểm soát viên")]
            Moderator = 1,

            [Display(Name = "Thành viên")]
            Member = 2



            Note: You can remove the attribute Display.



            Then, we create RolesExtensions class:



            public static class RolesExtensions

            public static async Task InitializeAsync(RoleManager<IdentityRole> roleManager)

            foreach (string roleName in Enum.GetNames(typeof(UserRoles)))

            if (!await roleManager.RoleExistsAsync(roleName))

            await roleManager.CreateAsync(new IdentityRole(roleName));






            Next, in the Startup.cs class, we run it:



             public void Configure(
            IApplicationBuilder app,
            IHostingEnvironment env,
            RoleManager<IdentityRole> roleManager)

            // other settings...

            app.UseMvc(routes =>

            routes.MapRoute(
            name: "default",
            template: "controller=Home/action=Index/id?");
            );

            var task = RolesExtensions.InitializeAsync(roleManager);
            task.Wait();



            Note: Configure requires a returned type void, so we need to create a task to initialize the user roles and we call Wait method.



            Do not change the returned type like this:



            public async void Configure(...)

            await RolesExtensions.InitializeAsync(roleManager);



            Source: Async/Await - Best Practices in Asynchronous Programming



            In the ConfigureServices method, these configurations would NOT work (we cannot use User.IsInRole correctly):



            services.AddDefaultIdentity<ApplicationUser>()
            //.AddRoles<IdentityRole>()
            //.AddRoleManager<RoleManager<IdentityRole>>()
            .AddEntityFrameworkStores<ApplicationDbContext>();


            I don't know why but AddRoles and AddRoleManager don't support to check role for a user (User.IsInRole).



            In this case, we need to register service like this:



            services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();


            By using this way, we create 3 user roles in the databse:



            1



            When register new user, we just need to call:



            await _userManager.AddToRoleAsync(user, nameof(UserRoles.Administrator));



            Finally, we can use [Authorize(Roles = "Administrator")] and:



            if (User.IsInRole("Administrator"))

            // authorized


            // or
            if (User.IsInRole(nameof(UserRoles.Administrator)))

            // authorized


            // but
            if (User.IsInRole("ADMINISTRATOR"))

            // authorized



            P/S: There are a lot things which need to be implement to achieve this goal. So maybe I missed something in this example.






            share|improve this answer























            • Hey Tan, great answer. I guess I should have added that I want to use the newfangled services.AddDefaultIdentity rather than services.AddIdentity()… because I've seen too many conflicting stories online about what fluent methods need to follow AddIdentity to get it to work for various use cases.

              – Bob.at.Indigo.Health
              Nov 13 '18 at 20:02











            • Also, I think that your call to InitializeAsync my be prone to deadlock issues in ASP.NET. Take a look at this SO answer. This issue of calling an async method from the synchronous Startup methods is why my example code put all of the seed logic into the Controller code (so I wouldn't have to include the extra code needed to do it correctly from the Startup code).

              – Bob.at.Indigo.Health
              Nov 13 '18 at 20:16
















            1














            Ahh, there are some changes from ASP.NET Core version 2.0 to 2.1. AddDefaultIdentity is the one.



            I don't know where to start from your code, so, I will provide an example to create and get user role(s).



            Let's create UserRoles first:



            public enum UserRoles

            [Display(Name = "Quản trị viên")]
            Administrator = 0,

            [Display(Name = "Kiểm soát viên")]
            Moderator = 1,

            [Display(Name = "Thành viên")]
            Member = 2



            Note: You can remove the attribute Display.



            Then, we create RolesExtensions class:



            public static class RolesExtensions

            public static async Task InitializeAsync(RoleManager<IdentityRole> roleManager)

            foreach (string roleName in Enum.GetNames(typeof(UserRoles)))

            if (!await roleManager.RoleExistsAsync(roleName))

            await roleManager.CreateAsync(new IdentityRole(roleName));






            Next, in the Startup.cs class, we run it:



             public void Configure(
            IApplicationBuilder app,
            IHostingEnvironment env,
            RoleManager<IdentityRole> roleManager)

            // other settings...

            app.UseMvc(routes =>

            routes.MapRoute(
            name: "default",
            template: "controller=Home/action=Index/id?");
            );

            var task = RolesExtensions.InitializeAsync(roleManager);
            task.Wait();



            Note: Configure requires a returned type void, so we need to create a task to initialize the user roles and we call Wait method.



            Do not change the returned type like this:



            public async void Configure(...)

            await RolesExtensions.InitializeAsync(roleManager);



            Source: Async/Await - Best Practices in Asynchronous Programming



            In the ConfigureServices method, these configurations would NOT work (we cannot use User.IsInRole correctly):



            services.AddDefaultIdentity<ApplicationUser>()
            //.AddRoles<IdentityRole>()
            //.AddRoleManager<RoleManager<IdentityRole>>()
            .AddEntityFrameworkStores<ApplicationDbContext>();


            I don't know why but AddRoles and AddRoleManager don't support to check role for a user (User.IsInRole).



            In this case, we need to register service like this:



            services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();


            By using this way, we create 3 user roles in the databse:



            1



            When register new user, we just need to call:



            await _userManager.AddToRoleAsync(user, nameof(UserRoles.Administrator));



            Finally, we can use [Authorize(Roles = "Administrator")] and:



            if (User.IsInRole("Administrator"))

            // authorized


            // or
            if (User.IsInRole(nameof(UserRoles.Administrator)))

            // authorized


            // but
            if (User.IsInRole("ADMINISTRATOR"))

            // authorized



            P/S: There are a lot things which need to be implement to achieve this goal. So maybe I missed something in this example.






            share|improve this answer























            • Hey Tan, great answer. I guess I should have added that I want to use the newfangled services.AddDefaultIdentity rather than services.AddIdentity()… because I've seen too many conflicting stories online about what fluent methods need to follow AddIdentity to get it to work for various use cases.

              – Bob.at.Indigo.Health
              Nov 13 '18 at 20:02











            • Also, I think that your call to InitializeAsync my be prone to deadlock issues in ASP.NET. Take a look at this SO answer. This issue of calling an async method from the synchronous Startup methods is why my example code put all of the seed logic into the Controller code (so I wouldn't have to include the extra code needed to do it correctly from the Startup code).

              – Bob.at.Indigo.Health
              Nov 13 '18 at 20:16














            1












            1








            1







            Ahh, there are some changes from ASP.NET Core version 2.0 to 2.1. AddDefaultIdentity is the one.



            I don't know where to start from your code, so, I will provide an example to create and get user role(s).



            Let's create UserRoles first:



            public enum UserRoles

            [Display(Name = "Quản trị viên")]
            Administrator = 0,

            [Display(Name = "Kiểm soát viên")]
            Moderator = 1,

            [Display(Name = "Thành viên")]
            Member = 2



            Note: You can remove the attribute Display.



            Then, we create RolesExtensions class:



            public static class RolesExtensions

            public static async Task InitializeAsync(RoleManager<IdentityRole> roleManager)

            foreach (string roleName in Enum.GetNames(typeof(UserRoles)))

            if (!await roleManager.RoleExistsAsync(roleName))

            await roleManager.CreateAsync(new IdentityRole(roleName));






            Next, in the Startup.cs class, we run it:



             public void Configure(
            IApplicationBuilder app,
            IHostingEnvironment env,
            RoleManager<IdentityRole> roleManager)

            // other settings...

            app.UseMvc(routes =>

            routes.MapRoute(
            name: "default",
            template: "controller=Home/action=Index/id?");
            );

            var task = RolesExtensions.InitializeAsync(roleManager);
            task.Wait();



            Note: Configure requires a returned type void, so we need to create a task to initialize the user roles and we call Wait method.



            Do not change the returned type like this:



            public async void Configure(...)

            await RolesExtensions.InitializeAsync(roleManager);



            Source: Async/Await - Best Practices in Asynchronous Programming



            In the ConfigureServices method, these configurations would NOT work (we cannot use User.IsInRole correctly):



            services.AddDefaultIdentity<ApplicationUser>()
            //.AddRoles<IdentityRole>()
            //.AddRoleManager<RoleManager<IdentityRole>>()
            .AddEntityFrameworkStores<ApplicationDbContext>();


            I don't know why but AddRoles and AddRoleManager don't support to check role for a user (User.IsInRole).



            In this case, we need to register service like this:



            services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();


            By using this way, we create 3 user roles in the databse:



            1



            When register new user, we just need to call:



            await _userManager.AddToRoleAsync(user, nameof(UserRoles.Administrator));



            Finally, we can use [Authorize(Roles = "Administrator")] and:



            if (User.IsInRole("Administrator"))

            // authorized


            // or
            if (User.IsInRole(nameof(UserRoles.Administrator)))

            // authorized


            // but
            if (User.IsInRole("ADMINISTRATOR"))

            // authorized



            P/S: There are a lot things which need to be implement to achieve this goal. So maybe I missed something in this example.






            share|improve this answer













            Ahh, there are some changes from ASP.NET Core version 2.0 to 2.1. AddDefaultIdentity is the one.



            I don't know where to start from your code, so, I will provide an example to create and get user role(s).



            Let's create UserRoles first:



            public enum UserRoles

            [Display(Name = "Quản trị viên")]
            Administrator = 0,

            [Display(Name = "Kiểm soát viên")]
            Moderator = 1,

            [Display(Name = "Thành viên")]
            Member = 2



            Note: You can remove the attribute Display.



            Then, we create RolesExtensions class:



            public static class RolesExtensions

            public static async Task InitializeAsync(RoleManager<IdentityRole> roleManager)

            foreach (string roleName in Enum.GetNames(typeof(UserRoles)))

            if (!await roleManager.RoleExistsAsync(roleName))

            await roleManager.CreateAsync(new IdentityRole(roleName));






            Next, in the Startup.cs class, we run it:



             public void Configure(
            IApplicationBuilder app,
            IHostingEnvironment env,
            RoleManager<IdentityRole> roleManager)

            // other settings...

            app.UseMvc(routes =>

            routes.MapRoute(
            name: "default",
            template: "controller=Home/action=Index/id?");
            );

            var task = RolesExtensions.InitializeAsync(roleManager);
            task.Wait();



            Note: Configure requires a returned type void, so we need to create a task to initialize the user roles and we call Wait method.



            Do not change the returned type like this:



            public async void Configure(...)

            await RolesExtensions.InitializeAsync(roleManager);



            Source: Async/Await - Best Practices in Asynchronous Programming



            In the ConfigureServices method, these configurations would NOT work (we cannot use User.IsInRole correctly):



            services.AddDefaultIdentity<ApplicationUser>()
            //.AddRoles<IdentityRole>()
            //.AddRoleManager<RoleManager<IdentityRole>>()
            .AddEntityFrameworkStores<ApplicationDbContext>();


            I don't know why but AddRoles and AddRoleManager don't support to check role for a user (User.IsInRole).



            In this case, we need to register service like this:



            services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();


            By using this way, we create 3 user roles in the databse:



            1



            When register new user, we just need to call:



            await _userManager.AddToRoleAsync(user, nameof(UserRoles.Administrator));



            Finally, we can use [Authorize(Roles = "Administrator")] and:



            if (User.IsInRole("Administrator"))

            // authorized


            // or
            if (User.IsInRole(nameof(UserRoles.Administrator)))

            // authorized


            // but
            if (User.IsInRole("ADMINISTRATOR"))

            // authorized



            P/S: There are a lot things which need to be implement to achieve this goal. So maybe I missed something in this example.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 13 '18 at 8:09









            FooFoo

            1




            1












            • Hey Tan, great answer. I guess I should have added that I want to use the newfangled services.AddDefaultIdentity rather than services.AddIdentity()… because I've seen too many conflicting stories online about what fluent methods need to follow AddIdentity to get it to work for various use cases.

              – Bob.at.Indigo.Health
              Nov 13 '18 at 20:02











            • Also, I think that your call to InitializeAsync my be prone to deadlock issues in ASP.NET. Take a look at this SO answer. This issue of calling an async method from the synchronous Startup methods is why my example code put all of the seed logic into the Controller code (so I wouldn't have to include the extra code needed to do it correctly from the Startup code).

              – Bob.at.Indigo.Health
              Nov 13 '18 at 20:16


















            • Hey Tan, great answer. I guess I should have added that I want to use the newfangled services.AddDefaultIdentity rather than services.AddIdentity()… because I've seen too many conflicting stories online about what fluent methods need to follow AddIdentity to get it to work for various use cases.

              – Bob.at.Indigo.Health
              Nov 13 '18 at 20:02











            • Also, I think that your call to InitializeAsync my be prone to deadlock issues in ASP.NET. Take a look at this SO answer. This issue of calling an async method from the synchronous Startup methods is why my example code put all of the seed logic into the Controller code (so I wouldn't have to include the extra code needed to do it correctly from the Startup code).

              – Bob.at.Indigo.Health
              Nov 13 '18 at 20:16

















            Hey Tan, great answer. I guess I should have added that I want to use the newfangled services.AddDefaultIdentity rather than services.AddIdentity()… because I've seen too many conflicting stories online about what fluent methods need to follow AddIdentity to get it to work for various use cases.

            – Bob.at.Indigo.Health
            Nov 13 '18 at 20:02





            Hey Tan, great answer. I guess I should have added that I want to use the newfangled services.AddDefaultIdentity rather than services.AddIdentity()… because I've seen too many conflicting stories online about what fluent methods need to follow AddIdentity to get it to work for various use cases.

            – Bob.at.Indigo.Health
            Nov 13 '18 at 20:02













            Also, I think that your call to InitializeAsync my be prone to deadlock issues in ASP.NET. Take a look at this SO answer. This issue of calling an async method from the synchronous Startup methods is why my example code put all of the seed logic into the Controller code (so I wouldn't have to include the extra code needed to do it correctly from the Startup code).

            – Bob.at.Indigo.Health
            Nov 13 '18 at 20:16






            Also, I think that your call to InitializeAsync my be prone to deadlock issues in ASP.NET. Take a look at this SO answer. This issue of calling an async method from the synchronous Startup methods is why my example code put all of the seed logic into the Controller code (so I wouldn't have to include the extra code needed to do it correctly from the Startup code).

            – Bob.at.Indigo.Health
            Nov 13 '18 at 20:16


















            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53271496%2fasp-net-core-identity-2-user-isinrole-always-returns-false%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

            Edmonton

            Crossroads (UK TV series)