Reputation: 455
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?
Upvotes: 3
Views: 3300
Reputation: 29976
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>();
Upvotes: 2