ASP.NET Core Identity - UserClaims, UserRoles and RoleClaims












0















I'm setting up an application using ASP.NET Core Identity, and despite reading thoroughly on the topic, I'm struggling to find the right fit for my requirements.



Users familiar with the subreddit concept of Reddit might understand my requirement well, as the concepts are very similar.



Essentially, I have a requirement where a user can be a moderator of one "area" (similar to a subreddit) and just be a "user" in another "area".



What it boils down to is that when a user logs in, I need to know their roles in every area.



I'm struggling with what this actually means in terms of ASP.NET Core Identity's AspNetUserClaims and AspNetRoles / AspNetUserRoles.



I'm considering defining AspNetRoles like so:



Id     Name
1000 User
2000 Junior Moderator
3000 Senior Moderator


Then setting up AspNetUserClaims like so:



Id     UserId     ClaimType      ClaimValue
1 1 area:public1 1000
2 1 area:private1 2000


This would mean that the user with ID 1 is a "user" of the area "public1" and a junior moderator of the area "private1".



I have a number of problems with this.



First, this breaks first normal form by trying to stuff two values into "ClaimType".



Second, there is no referential integrity in place.



Looking closer at AspNetUserRoles, I see a many-to-many relationship between users and roles. I don't see how this would work unless I define every possible role for every possible area as an AspNetRole. Even then, it's still unclear how I would tie this to AspNetUserClaims in a referentially-secure manner.



To complicate matters, it's unclear whether I just need Claims or a combination of Claims and Roles. The following question touches on the subject, but I'm not seeing a clear path based on my requirements:



Best Practices for Roles vs. Claims in ASP.NET Identity



There's no reason I can't solve the issues I'm experiencing by implementing a solution like the above with claims like "area:public1", but this goes against everything I understand about systems design.



Given the requirements described above, what would be the recommended implementation in ASP.NET Core Identity?










share|improve this question



























    0















    I'm setting up an application using ASP.NET Core Identity, and despite reading thoroughly on the topic, I'm struggling to find the right fit for my requirements.



    Users familiar with the subreddit concept of Reddit might understand my requirement well, as the concepts are very similar.



    Essentially, I have a requirement where a user can be a moderator of one "area" (similar to a subreddit) and just be a "user" in another "area".



    What it boils down to is that when a user logs in, I need to know their roles in every area.



    I'm struggling with what this actually means in terms of ASP.NET Core Identity's AspNetUserClaims and AspNetRoles / AspNetUserRoles.



    I'm considering defining AspNetRoles like so:



    Id     Name
    1000 User
    2000 Junior Moderator
    3000 Senior Moderator


    Then setting up AspNetUserClaims like so:



    Id     UserId     ClaimType      ClaimValue
    1 1 area:public1 1000
    2 1 area:private1 2000


    This would mean that the user with ID 1 is a "user" of the area "public1" and a junior moderator of the area "private1".



    I have a number of problems with this.



    First, this breaks first normal form by trying to stuff two values into "ClaimType".



    Second, there is no referential integrity in place.



    Looking closer at AspNetUserRoles, I see a many-to-many relationship between users and roles. I don't see how this would work unless I define every possible role for every possible area as an AspNetRole. Even then, it's still unclear how I would tie this to AspNetUserClaims in a referentially-secure manner.



    To complicate matters, it's unclear whether I just need Claims or a combination of Claims and Roles. The following question touches on the subject, but I'm not seeing a clear path based on my requirements:



    Best Practices for Roles vs. Claims in ASP.NET Identity



    There's no reason I can't solve the issues I'm experiencing by implementing a solution like the above with claims like "area:public1", but this goes against everything I understand about systems design.



    Given the requirements described above, what would be the recommended implementation in ASP.NET Core Identity?










    share|improve this question

























      0












      0








      0








      I'm setting up an application using ASP.NET Core Identity, and despite reading thoroughly on the topic, I'm struggling to find the right fit for my requirements.



      Users familiar with the subreddit concept of Reddit might understand my requirement well, as the concepts are very similar.



      Essentially, I have a requirement where a user can be a moderator of one "area" (similar to a subreddit) and just be a "user" in another "area".



      What it boils down to is that when a user logs in, I need to know their roles in every area.



      I'm struggling with what this actually means in terms of ASP.NET Core Identity's AspNetUserClaims and AspNetRoles / AspNetUserRoles.



      I'm considering defining AspNetRoles like so:



      Id     Name
      1000 User
      2000 Junior Moderator
      3000 Senior Moderator


      Then setting up AspNetUserClaims like so:



      Id     UserId     ClaimType      ClaimValue
      1 1 area:public1 1000
      2 1 area:private1 2000


      This would mean that the user with ID 1 is a "user" of the area "public1" and a junior moderator of the area "private1".



      I have a number of problems with this.



      First, this breaks first normal form by trying to stuff two values into "ClaimType".



      Second, there is no referential integrity in place.



      Looking closer at AspNetUserRoles, I see a many-to-many relationship between users and roles. I don't see how this would work unless I define every possible role for every possible area as an AspNetRole. Even then, it's still unclear how I would tie this to AspNetUserClaims in a referentially-secure manner.



      To complicate matters, it's unclear whether I just need Claims or a combination of Claims and Roles. The following question touches on the subject, but I'm not seeing a clear path based on my requirements:



      Best Practices for Roles vs. Claims in ASP.NET Identity



      There's no reason I can't solve the issues I'm experiencing by implementing a solution like the above with claims like "area:public1", but this goes against everything I understand about systems design.



      Given the requirements described above, what would be the recommended implementation in ASP.NET Core Identity?










      share|improve this question














      I'm setting up an application using ASP.NET Core Identity, and despite reading thoroughly on the topic, I'm struggling to find the right fit for my requirements.



      Users familiar with the subreddit concept of Reddit might understand my requirement well, as the concepts are very similar.



      Essentially, I have a requirement where a user can be a moderator of one "area" (similar to a subreddit) and just be a "user" in another "area".



      What it boils down to is that when a user logs in, I need to know their roles in every area.



      I'm struggling with what this actually means in terms of ASP.NET Core Identity's AspNetUserClaims and AspNetRoles / AspNetUserRoles.



      I'm considering defining AspNetRoles like so:



      Id     Name
      1000 User
      2000 Junior Moderator
      3000 Senior Moderator


      Then setting up AspNetUserClaims like so:



      Id     UserId     ClaimType      ClaimValue
      1 1 area:public1 1000
      2 1 area:private1 2000


      This would mean that the user with ID 1 is a "user" of the area "public1" and a junior moderator of the area "private1".



      I have a number of problems with this.



      First, this breaks first normal form by trying to stuff two values into "ClaimType".



      Second, there is no referential integrity in place.



      Looking closer at AspNetUserRoles, I see a many-to-many relationship between users and roles. I don't see how this would work unless I define every possible role for every possible area as an AspNetRole. Even then, it's still unclear how I would tie this to AspNetUserClaims in a referentially-secure manner.



      To complicate matters, it's unclear whether I just need Claims or a combination of Claims and Roles. The following question touches on the subject, but I'm not seeing a clear path based on my requirements:



      Best Practices for Roles vs. Claims in ASP.NET Identity



      There's no reason I can't solve the issues I'm experiencing by implementing a solution like the above with claims like "area:public1", but this goes against everything I understand about systems design.



      Given the requirements described above, what would be the recommended implementation in ASP.NET Core Identity?







      asp.net-core asp.net-identity






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 14 '18 at 23:17









      Jon HallidayJon Halliday

      205




      205
























          1 Answer
          1






          active

          oldest

          votes


















          1















          This would mean that the user with ID 1 is a "user" of the area
          "public1" and a junior moderator of the area "private1".




          If you want to achieve the User with Id 1 has User Role, and the User Role has claims public1 as area type.



          You could try code below to configure the data.



              public class HomeController : Controller
          {
          private readonly UserManager<IdentityUser> _userManager;
          private readonly RoleManager<IdentityRole> _roleManager;
          public HomeController(UserManager<IdentityUser> userManager
          , RoleManager<IdentityRole> roleManager)
          {
          _userManager = userManager;
          _roleManager = roleManager;
          }
          public async Task<IActionResult> Prepare()
          {
          var userRole = await _roleManager.CreateAsync(new IdentityRole("User"));
          var role = await _roleManager.FindByNameAsync("User");
          var roleClaims = await _roleManager.AddClaimAsync(role, new Claim("area", "public1"));
          var user = await _userManager.FindByNameAsync("UserName");

          var roleToUser = await _userManager.AddToRoleAsync(user, "User");
          return Ok("ok");
          }


          Then, get the claims for the user by



              public async Task<IActionResult> Index()
          {
          var user = await _userManager.FindByNameAsync("UserName");
          var roles = await _userManager.GetRolesAsync(user);

          var roleClaims = new List<Claim>();
          foreach (var roleName in roles)
          {
          var role = await _roleManager.FindByNameAsync(roleName);
          var claims = await _roleManager.GetClaimsAsync(role);
          roleClaims.AddRange(claims);
          }

          return View();
          }


          For above code, you need to configure .AddRoles<IdentityRole>()



                  services.AddDefaultIdentity<IdentityUser>()
          .AddRoles<IdentityRole>()
          .AddEntityFrameworkStores<ApplicationDbContext>();





          share|improve this answer
























          • Would it be considered good practice to have foreign keys pointing back to the AspNetRoleClaims table? Is this even possible? The reason is that I have an Area table that represents Areas with their own IDs, so behind the scenes "public1" might have an AreaId of 6. So I'd like to have a relationship between Area and RoleClaim in that case. Does this make sense?

            – Jon Halliday
            Nov 16 '18 at 13:59











          • @JonHalliday of course, it is possible, but it is not recommended, otherwise, you will need to implement your own RoleManager to retrive the public1 by id 6

            – Tao Zhou
            Nov 16 '18 at 14:27











          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%2f53310202%2fasp-net-core-identity-userclaims-userroles-and-roleclaims%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1















          This would mean that the user with ID 1 is a "user" of the area
          "public1" and a junior moderator of the area "private1".




          If you want to achieve the User with Id 1 has User Role, and the User Role has claims public1 as area type.



          You could try code below to configure the data.



              public class HomeController : Controller
          {
          private readonly UserManager<IdentityUser> _userManager;
          private readonly RoleManager<IdentityRole> _roleManager;
          public HomeController(UserManager<IdentityUser> userManager
          , RoleManager<IdentityRole> roleManager)
          {
          _userManager = userManager;
          _roleManager = roleManager;
          }
          public async Task<IActionResult> Prepare()
          {
          var userRole = await _roleManager.CreateAsync(new IdentityRole("User"));
          var role = await _roleManager.FindByNameAsync("User");
          var roleClaims = await _roleManager.AddClaimAsync(role, new Claim("area", "public1"));
          var user = await _userManager.FindByNameAsync("UserName");

          var roleToUser = await _userManager.AddToRoleAsync(user, "User");
          return Ok("ok");
          }


          Then, get the claims for the user by



              public async Task<IActionResult> Index()
          {
          var user = await _userManager.FindByNameAsync("UserName");
          var roles = await _userManager.GetRolesAsync(user);

          var roleClaims = new List<Claim>();
          foreach (var roleName in roles)
          {
          var role = await _roleManager.FindByNameAsync(roleName);
          var claims = await _roleManager.GetClaimsAsync(role);
          roleClaims.AddRange(claims);
          }

          return View();
          }


          For above code, you need to configure .AddRoles<IdentityRole>()



                  services.AddDefaultIdentity<IdentityUser>()
          .AddRoles<IdentityRole>()
          .AddEntityFrameworkStores<ApplicationDbContext>();





          share|improve this answer
























          • Would it be considered good practice to have foreign keys pointing back to the AspNetRoleClaims table? Is this even possible? The reason is that I have an Area table that represents Areas with their own IDs, so behind the scenes "public1" might have an AreaId of 6. So I'd like to have a relationship between Area and RoleClaim in that case. Does this make sense?

            – Jon Halliday
            Nov 16 '18 at 13:59











          • @JonHalliday of course, it is possible, but it is not recommended, otherwise, you will need to implement your own RoleManager to retrive the public1 by id 6

            – Tao Zhou
            Nov 16 '18 at 14:27
















          1















          This would mean that the user with ID 1 is a "user" of the area
          "public1" and a junior moderator of the area "private1".




          If you want to achieve the User with Id 1 has User Role, and the User Role has claims public1 as area type.



          You could try code below to configure the data.



              public class HomeController : Controller
          {
          private readonly UserManager<IdentityUser> _userManager;
          private readonly RoleManager<IdentityRole> _roleManager;
          public HomeController(UserManager<IdentityUser> userManager
          , RoleManager<IdentityRole> roleManager)
          {
          _userManager = userManager;
          _roleManager = roleManager;
          }
          public async Task<IActionResult> Prepare()
          {
          var userRole = await _roleManager.CreateAsync(new IdentityRole("User"));
          var role = await _roleManager.FindByNameAsync("User");
          var roleClaims = await _roleManager.AddClaimAsync(role, new Claim("area", "public1"));
          var user = await _userManager.FindByNameAsync("UserName");

          var roleToUser = await _userManager.AddToRoleAsync(user, "User");
          return Ok("ok");
          }


          Then, get the claims for the user by



              public async Task<IActionResult> Index()
          {
          var user = await _userManager.FindByNameAsync("UserName");
          var roles = await _userManager.GetRolesAsync(user);

          var roleClaims = new List<Claim>();
          foreach (var roleName in roles)
          {
          var role = await _roleManager.FindByNameAsync(roleName);
          var claims = await _roleManager.GetClaimsAsync(role);
          roleClaims.AddRange(claims);
          }

          return View();
          }


          For above code, you need to configure .AddRoles<IdentityRole>()



                  services.AddDefaultIdentity<IdentityUser>()
          .AddRoles<IdentityRole>()
          .AddEntityFrameworkStores<ApplicationDbContext>();





          share|improve this answer
























          • Would it be considered good practice to have foreign keys pointing back to the AspNetRoleClaims table? Is this even possible? The reason is that I have an Area table that represents Areas with their own IDs, so behind the scenes "public1" might have an AreaId of 6. So I'd like to have a relationship between Area and RoleClaim in that case. Does this make sense?

            – Jon Halliday
            Nov 16 '18 at 13:59











          • @JonHalliday of course, it is possible, but it is not recommended, otherwise, you will need to implement your own RoleManager to retrive the public1 by id 6

            – Tao Zhou
            Nov 16 '18 at 14:27














          1












          1








          1








          This would mean that the user with ID 1 is a "user" of the area
          "public1" and a junior moderator of the area "private1".




          If you want to achieve the User with Id 1 has User Role, and the User Role has claims public1 as area type.



          You could try code below to configure the data.



              public class HomeController : Controller
          {
          private readonly UserManager<IdentityUser> _userManager;
          private readonly RoleManager<IdentityRole> _roleManager;
          public HomeController(UserManager<IdentityUser> userManager
          , RoleManager<IdentityRole> roleManager)
          {
          _userManager = userManager;
          _roleManager = roleManager;
          }
          public async Task<IActionResult> Prepare()
          {
          var userRole = await _roleManager.CreateAsync(new IdentityRole("User"));
          var role = await _roleManager.FindByNameAsync("User");
          var roleClaims = await _roleManager.AddClaimAsync(role, new Claim("area", "public1"));
          var user = await _userManager.FindByNameAsync("UserName");

          var roleToUser = await _userManager.AddToRoleAsync(user, "User");
          return Ok("ok");
          }


          Then, get the claims for the user by



              public async Task<IActionResult> Index()
          {
          var user = await _userManager.FindByNameAsync("UserName");
          var roles = await _userManager.GetRolesAsync(user);

          var roleClaims = new List<Claim>();
          foreach (var roleName in roles)
          {
          var role = await _roleManager.FindByNameAsync(roleName);
          var claims = await _roleManager.GetClaimsAsync(role);
          roleClaims.AddRange(claims);
          }

          return View();
          }


          For above code, you need to configure .AddRoles<IdentityRole>()



                  services.AddDefaultIdentity<IdentityUser>()
          .AddRoles<IdentityRole>()
          .AddEntityFrameworkStores<ApplicationDbContext>();





          share|improve this answer














          This would mean that the user with ID 1 is a "user" of the area
          "public1" and a junior moderator of the area "private1".




          If you want to achieve the User with Id 1 has User Role, and the User Role has claims public1 as area type.



          You could try code below to configure the data.



              public class HomeController : Controller
          {
          private readonly UserManager<IdentityUser> _userManager;
          private readonly RoleManager<IdentityRole> _roleManager;
          public HomeController(UserManager<IdentityUser> userManager
          , RoleManager<IdentityRole> roleManager)
          {
          _userManager = userManager;
          _roleManager = roleManager;
          }
          public async Task<IActionResult> Prepare()
          {
          var userRole = await _roleManager.CreateAsync(new IdentityRole("User"));
          var role = await _roleManager.FindByNameAsync("User");
          var roleClaims = await _roleManager.AddClaimAsync(role, new Claim("area", "public1"));
          var user = await _userManager.FindByNameAsync("UserName");

          var roleToUser = await _userManager.AddToRoleAsync(user, "User");
          return Ok("ok");
          }


          Then, get the claims for the user by



              public async Task<IActionResult> Index()
          {
          var user = await _userManager.FindByNameAsync("UserName");
          var roles = await _userManager.GetRolesAsync(user);

          var roleClaims = new List<Claim>();
          foreach (var roleName in roles)
          {
          var role = await _roleManager.FindByNameAsync(roleName);
          var claims = await _roleManager.GetClaimsAsync(role);
          roleClaims.AddRange(claims);
          }

          return View();
          }


          For above code, you need to configure .AddRoles<IdentityRole>()



                  services.AddDefaultIdentity<IdentityUser>()
          .AddRoles<IdentityRole>()
          .AddEntityFrameworkStores<ApplicationDbContext>();






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 16 '18 at 5:52









          Tao ZhouTao Zhou

          6,50831331




          6,50831331













          • Would it be considered good practice to have foreign keys pointing back to the AspNetRoleClaims table? Is this even possible? The reason is that I have an Area table that represents Areas with their own IDs, so behind the scenes "public1" might have an AreaId of 6. So I'd like to have a relationship between Area and RoleClaim in that case. Does this make sense?

            – Jon Halliday
            Nov 16 '18 at 13:59











          • @JonHalliday of course, it is possible, but it is not recommended, otherwise, you will need to implement your own RoleManager to retrive the public1 by id 6

            – Tao Zhou
            Nov 16 '18 at 14:27



















          • Would it be considered good practice to have foreign keys pointing back to the AspNetRoleClaims table? Is this even possible? The reason is that I have an Area table that represents Areas with their own IDs, so behind the scenes "public1" might have an AreaId of 6. So I'd like to have a relationship between Area and RoleClaim in that case. Does this make sense?

            – Jon Halliday
            Nov 16 '18 at 13:59











          • @JonHalliday of course, it is possible, but it is not recommended, otherwise, you will need to implement your own RoleManager to retrive the public1 by id 6

            – Tao Zhou
            Nov 16 '18 at 14:27

















          Would it be considered good practice to have foreign keys pointing back to the AspNetRoleClaims table? Is this even possible? The reason is that I have an Area table that represents Areas with their own IDs, so behind the scenes "public1" might have an AreaId of 6. So I'd like to have a relationship between Area and RoleClaim in that case. Does this make sense?

          – Jon Halliday
          Nov 16 '18 at 13:59





          Would it be considered good practice to have foreign keys pointing back to the AspNetRoleClaims table? Is this even possible? The reason is that I have an Area table that represents Areas with their own IDs, so behind the scenes "public1" might have an AreaId of 6. So I'd like to have a relationship between Area and RoleClaim in that case. Does this make sense?

          – Jon Halliday
          Nov 16 '18 at 13:59













          @JonHalliday of course, it is possible, but it is not recommended, otherwise, you will need to implement your own RoleManager to retrive the public1 by id 6

          – Tao Zhou
          Nov 16 '18 at 14:27





          @JonHalliday of course, it is possible, but it is not recommended, otherwise, you will need to implement your own RoleManager to retrive the public1 by id 6

          – Tao Zhou
          Nov 16 '18 at 14:27




















          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%2f53310202%2fasp-net-core-identity-userclaims-userroles-and-roleclaims%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

          Xamarin.iOS Cant Deploy on Iphone

          Glorious Revolution

          Dulmage-Mendelsohn matrix decomposition in Python