Using .net Core Identity with my business - asp.net-core

I have a tree which is in a table named cartable.
I want to use .net core Identity to grant some permissions to this tree like these:
Each Role has some permissions such as "Read Letter","Create a Letter","Delete a Letter" and so on
Each User may have a one of the Role on a Node of Cartable table in a
specific Date i.e from 06/01/2019 to 05/10/2020
would you please help me how to implement it?
should I use Claim or I have to customize UserRole table of .net Identity
Thanks

Instead of having permissions based directly on roles,you can use Policy-based Authorization
You could define a policy in startup for each of the permissions. Each policy can require a role, so you would still use roles. Each policy can also require a claim where you keep the date for each user, and the policy rule can validate that the date in the claim is not out of range.
In the controller actions that correspond to your nodes, you decorate the action method with the Authorize attribute and specify the policy name as shown in the linked documentation.
[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseController : Controller
{
public IActionResult Login() => View();
public IActionResult Logout() => View();
}

Related

Get Claims from Extended UserClaim Table in Web Api using Microsoft Identity

i am working on ASP.Net 5 , web api project and using Microsoft Identity and jwt token based for my security management . I have already extended the user claim table and add a new row of isSelected to this table . I need to know , how can i just get the claims that has the isSelected == true from the table , is there any way that i can use the _signinManager services for this task? I can do like this for normal situation :
var claims = await _signinManager.ClaimsFactory.CreateAsync(user)
and get the ClaimPrincipals , but this will return all the claims whether the isSelected is true or false .
Thank you!
Some behaviors require customization. Like in your case, you want the default configuration to filter list of data based on a particular column name (isSelected) and only return the filtered list. The best way to approach this using a customized UserManager or SignInManager and create a method that will do just what you're asking for.
Here's an idea:
Create a method called IList<UserClaim> GetUserClaimsBasedOnSelection(bool isSelected, User user). All that this method should do is use the underlying Claims retrieving method and just filter that list to only return the selected claims. That's it. And then after you just register your configured SignInManager inside Program.cs or startup.cs by adding this service to your AddIdentity service configuration .AddSignInManager<YourSignInManager>()

ASP.NET Core Identity - NormalizedUserName, NormalizedEmail

While developing a multi-tenant app with ASP.NET Core I noticed that it brings 2 new indices: NormalizedUserName & NormalizedEmail.
The main problem is that it gets too difficult to have a unique user per tenant.
What I mean is having multiple users with the same UserName & Email but different TenantID.
In order to achieve this I have to remove those indices
public static void RemoveIndexes(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<ApplicationUser>(entity =>
{
var normalizedUserNameIndex = entity.HasIndex(u => new { u.NormalizedUserName }).Metadata;
entity.Metadata.RemoveIndex(normalizedUserNameIndex.Properties);
var normalizedEmailIndex = entity.HasIndex(u => new { u.NormalizedEmail }).Metadata;
entity.Metadata.RemoveIndex(normalizedEmailIndex.Properties);
});
}
My questions are:
What is the purpose of these 2 new indices?
What would it affect if we just remove them?
Is there anything we need to pay close attention to after removing them? (e.g. overriding default UserManager functionality or something to that effect)
First of all, I wouldn't change anything of the Identity Framework if I can't oversee the effects. If you insist, you can test what happens yourself. But, do you need to remove the fields?
If the relation of user-to-tenant is one-to-many, then tenantId should not be a field of ApplicationUser but rather be stored in a seperate table, like UserClaims.
You can add multiple tenantId's as claim of the same type, like http://tenant.company.com/Id. It will then become a collection of values, like what happens with roles.
If you don't want this then you can use different claimtypes, like http://tenant.company1.com/Id, http://tenant.company2.com/Id or something like that.
You can choose to include only claims that are linked to the tenant, which could be determined from the site binding or the url, for instance.
This design allows the user to login using the same password everywhere. Please note, this is about identity: who is the user? The user doesn't need to have a different password for every tenant.
It also makes it easier to change a password. Because I wonder, how does your scenario look like with multiple user records for each tenant? Will you update all records at once when a password changes? And how will you support 'forgot password' and other features?

.NET Core 2.1 MVC Identity Authorization - Different user roles for different parts

Currently, I'm working on a project management website. There is a SuperAdmin (role) in the system, who can create new projects. The SuperAdmin can assign users to these projects with different roles, like admin or observer. A user can take different roles for different projects or even no role at all.
For example:
User A is Admin for Project A
User A is Observer for Project B (read access only)
User A has no role Project C (can't access the project)
User B is Admin for Project B
User B is Observer for Project C (read access only)
The Identity does not seems like to support this behaviour. The claim-based authorization seems to support static claims, but not dynamic ones (accessing a project with an id).
I can create my own UserProjectRoles class which associates the user, projects and the roles and use that in the authorization handler (policy-based authorization), but I was wondering if this is the right solution. How would you solve this task?
Edit:
I ended up doing the following: I created a new UserProjectClaims table, which connencts the Users and a Projects and contains the role type as an enum (I will move the role/claim type to it's own table, this was just for the sake of testing).
public class UserProjectClaim
{
public int ProjectId { get; set; }
public Project Project { get; set; }
public int UserId { get; set; }
public AppUser User { get; set; }
public UserProjectClaimEnum ClaimType { get; set; }
}
Then I used this table in the AuthorizationHandler as seen in the Policy-based authorization tutorial:
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ProjectAdminRequirement requirement)
{
if (context.Resource is AuthorizationFilterContext authContext)
{
var projectId = Int32.Parse(authContext.HttpContext.Request.Query["projectId"]);
var userid = (await _userManager.GetUserAsync(context.User)).Id;
var claim = _dbContext.AppUsers.Include(i=>i.UserProjectClaims).Single(u=>u.Id==userid).UserProjectClaims.SingleOrDefault(p => p.ProjectId == projectId);
if (claim != null && claim.ClaimType == Data.Enums.UserProjectClaimEnum.ProjectAdmin)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
And it's working as expected.
After creating a new Web Application (MVC) with Individual User Accounts (VS2017), you will find tables such as AspNetRoles, AspNetRoleClaims, AspNetUserRoles, AspNetUserClaims as part of an Entity Framework Core IdentityContext.
The AccountController has a UserManager injected but does not have methods for maintenance of Roles & Claims. The Views (Pages), Controllers and Models are not supplied to manage the relationships, out of the box.
The good news is that the UserManager has all sorts of functionality to add claims & roles to users. AddClaimAsync, AddToRoleAsync, GetClaimsAsync, GetRolesAsync, GetUsersForClaimAsync, GetUsersInRoleAsync, RemoveClaimAsync, RemoveFromRoleAsync and versions that process claims/roles as an IEnumerable.
Short term solution: It should not be a difficult task to add methods to the AccountController or ManageController or even create a RolesController to support pages that manage these relationships.
Long term solution: Learn how to add templates to generate these items whenever you create a new MVC Identity project. Then show off by making it public in GitHub :) Or write an article about what you learned for other people in your situation.
Postscript: By creating a little middleware that you put in the request processing path, you can load the roles/claims for the current user that the rest of the request handling can refer to. A join table from Projects to Roles with perhaps read-role and write-role you can compare the roles required to the roles/claims the user has.
Technique: Here is a terrific explanation of custom policies and Authorization. In your case, the policy would test if the user has a role/claim that matches your project. Your roles above really are Project-Read, Project-Write. If neither, no access.

Combine users from database to authorization role

I found example on internet
Example:
[Authorize(Roles = "Admin, Super User")]
public ActionResult Index()
{
return View();
}
I have Users table on my database and it has user names.
If my users have "Admin" Role, I want them to reach Index actionresult otherwise no.
How can I combine my all users to Admin Role?
Solution if you download article you can do it
http://weblogs.asp.net/jgalloway/archive/2012/08/29/simplemembership-membership-providers-universal-providers-and-the-new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates.aspx
You need a RoleProvider for that. There's a default SqlRoleProvider that you could use and which would allow you to assign roles to your users.

SimpleMembership updating the "isconfirmed" flag

My Users table (the one that I created) has the following columns:
UserId,UserName,FirstName,LastName,DOB
After I ran this command
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "Users", "UserId", "UserName", autoCreateTables: true);
it created the required simple membership tables for me.
How would I go about "UnConfirming" an user or setting the "IsConfirmed" flag to false in the webpages_Membership using the new SimpleMembership API?
(Earlier, before going to simplemembership using the "Membership" class I could update an user using the api call : Membership.UpdateUser( user );)
I can't answer your question directly since I couldn't figure out a way to 'unconfirm' an account either. What I ended up doing, however, may help whoever finds this question.
I basically use Roles as a gatekeeper. Whenever I create a new account I add that user to a "User" role:
Roles.AddUserToRole(newUser.Username, "User");
I use the Authorize attribute to restrict access to my controllers (and use [AllowAnonymous] for actions that I want to be public -- like RegisterUser, for example). Then, inside each action I add a method to restrict access to only users that are in the "User" role.
if (!Roles.IsUserInRole(role))
{
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.Unauthorized));
}
NOTE: I'm using Web API, but if you're using MVC you should have a much easier time. Instead of manually checking if a user is in a role in each action you can just use the authorize attribute:
[Authorize(Roles = "User")]
When I want to "UnConfirm" a user I just remove them from the "User" role.
Roles.RemoveUserFromRole(user.Username, "User");
This way if a user comes crawling back I can just reactivate their account by adding them back as a User.
What I ended up doing was updating that table directly via a SQL query. Not sure if thats the recommended way of doing it, but that seemed to work for me.
(Thanks for your suggestion too).
Look at this blog post on adding email confirmation to SimpleMembership registration process, which covers how the confirmation process works. The cliff notes are that when you create a new user you set the flag that you want to use confirmation like this.
string confirmationToken =
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { Email = model.Email }, true);
When you do this the CreateUserAndAccount method returns a unique token that you can put in an email with a link so the user can confirm that they gave you a valid email address. When they click on the link it passes the token in the URL and the controller action can then confirm the token like this.
[AllowAnonymous]
public ActionResult RegisterConfirmation(string Id)
{
if (WebSecurity.ConfirmAccount(Id))
{
return RedirectToAction("ConfirmationSuccess");
}
return RedirectToAction("ConfirmationFailure");
}
The ConfirmAccount method checks if there is an uncomfirmed token that matches in the database and if there is it sets the isConfirmed flag to true. The user will not be able to logon until this is set to true.
set requireConfirmationToken to be true: (The 4th value shown below)
WebSecurity.CreateUserAndAccount(viewModel.UserName, viewModel.Password, null, true);
Source
http://www.w3schools.com/aspnet/met_websecurity_createuserandaccount.asp