How to get current user id, if i inherits from IdentityUser? - asp.net

I add some fields in IdentityUser like a
public class CustomUser: IdentityUser
{
public string field1 {get;set;}
public string field2 {get;set;}
}
after migration, on Sql Management studio i had all data, which i added with .OnModelCreating
But, How i can get any field from current authorized CustomUser (like a ID)
I try use
using Microsoft.AspNet.Identity;
CustomUser.Identity.GetUserId()
But it doesnt work.
Thanks for help!

In ASP.Net Core ,if your Controller inherits the Microsoft.AspNetCore.Mvc.Controller, you could get the IClaimsPrincipal from the User property and get the actual "Id" of the user,
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
ClaimsPrincipal currentUser = this.User;
var currentUserID = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
You can also get the data of all fields(include Id) from the database's User entity:
1.DI UserManager
private readonly UserManager<ApplicationUser> _userManager;
public HomeController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
2.Use it like below:
var id = userManager.GetUserId(User); // get user Id
var user = await userManager.GetUserAsync(User); // get user's all data

You need to first save user data in claims and then get authorized user data.
Add Claims
var identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
Get Claims
var userId = (HttpContext.Current.User.Identity as ClaimsIdentity).Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)

Related

Retrieve user information from ASPNetUsers table

I am really new to using Blazor WASM and the ASP.NET Core hosted. I have set up the login which stores all registered users to the ASPNetUsers table. I am wondering how I can then retrieve these users to display information to other users. For example I am looking to be able to have a user logged in who can then search all other users who have registered into the application as well. How might I go about displaying a list of all the users who have registered onto the application, stored in ASPNetUsers table
Options
Retrieve and send back
[HttpGet]
public async Task<ActionResult<IEnumerable<User>>> Get()
{
var result = userManager.Users.FirstOrDefault();
User x = new User();
x.Username = result.Email;
List<User> giveback = new List<User>();
giveback.Add(x);
return giveback;
}
To retrieve all users access the Users property on the UserManager:
var users = UserManager.Users.ToList();
The image in your post shows that you are only accessing the static members. You are not using an instance of UserManager.
You need to inject an instance into your controller:
readonly UserManager<ApplicationUser> _userManager;
public MyController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[HttpGet]
public ActionResult<IEnumerable<Ticket>> Get()
{
var user = _userManager.Users.FirstOrDefault();
}

How to get Identity User outside Razor Pages in Blazor Server-side?

I am working on a Blazor Server-Side application, using Microsoft Identity, Entity Framework and a multitenant approach with shared Db.
I have extended the IdentityUser class so that I could have the TenantId in the AspNetUser Table
public class ApplicationUser : IdentityUser
{
public int TenantId { get; set; }
}
}
Then I have applied a general query filter to my dbModel based on the TenantId
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Employee>().HasQueryFilter(a => a.TenantId == TenantId);
}
In my blazor page I can call this function
public async Task SetTenant()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
ApplicationUser = await UserManager.FindByNameAsync(user.Identity.Name);
var TenatId = ApplicationUser.TenantId;
}
Finally in my service I can get a list of Employees with the right TenantId
public Task<Employee[]> GetEmployees(int TenatntID)
{
using (var ctx = new ProgramDbContext(TenantId))
{
return Task.FromResult(ctx.Employee.Select(d => new Employee
{
Id = d.Id,
TenantId = d.TenantId,
Name= d.Name,
}).ToArray());
}
}
With this approach, everytime I want to call a function to get DB's Data, I need to identity the user and get the TenantId, then call the specific function and pass the tenantID to it.
I would like to know if my approach is completely wrong to implement this type of solution, for example:
Is it possible to add a Singleton service of an ApplicationUser, so that once is is identified after login, i can inject the service in every class where i need the ApplicationUser.TenantId?
Is it possible to identify and authenticate the Application User outside a blazor class? for example a plain C# class? I was able to pass the AuthenticationStateProvider and UserManager in the constructor of my Service class, but I cant await a function inside the constructor to actually get the ApplicationUser object.
public CaronteWebService(AuthenticationStateProvider authenticationStateProvider, UserManager userManager)
{
_AuthenticationStateProvider = authenticationStateProvider;
_userManager = userManager;
}
UserManager<ApplicationUser> _userManager;
public ApplicationUser ApplicationUser { get; set; }
AuthenticationStateProvider _AuthenticationStateProvider { get; set; }

Asp.net Identity DbContext / Repository Issue

I am using Asp.Net identity within my MVC app. I can see that this has it's own ApplicationDbContext - albeit it is connected to the same SQL db as my own DbContext I am using elsewhere.
So I am trying to access some of my own data via my own code within the AccountController - it does not seem to work I presume because of some confusion over which DBContext it thinks is active?
My Code :
public class AccountController : Controller
{
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
private PostageManager postmgr;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, PostageManager _postmgr)
{
UserManager = userManager;
SignInManager = signInManager;
postmgr = _postmgr;
}
public ApplicationSignInManager SignInManager
{
get
{
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
//create select list items for countries drop down
List<SelectListItem> countries;
countries = postmgr.GetCountries().Select(item => new SelectListItem
{
Value = item.Country,
Text = item.Country
}).ToList();
countries.Insert(0, new SelectListItem { Value = string.Empty, Text = "Select delivery country or region...", Selected = true });
RegisterViewModel mode = new RegisterViewModel
{
Countries = countries
};
return View();
}
}
}
PostageManager is just a class that sits over my DAL to fetch some data (which uses repository pattern) - I'm using just a kind of pass through method to grab a list of countries, and using it in exactly the same way I have in other controllers which works fine. Underneath that class is my repository code that is linked to my default connection string (DBContext). It's balking at the following line with a null reference exception, I think postmgr is null :
countries = postmgr.GetCountries().Select(item => new SelectListItem
In reverse to get access to the identity data within my own controllers I have done the following :
public BasketController(BasketManager _mgr, PostageManager _postmgr, ProductManager _prodmgr)
{
mgr = _mgr;
postmgr = _postmgr;
prodmgr = _prodmgr;
shopper = Cart.GetShopperId();
this.applicationDbContext = new ApplicationDbContext();
this.userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(this.applicationDbContext));
}
protected ApplicationDbContext applicationDbContext { get; set; }
protected UserManager<ApplicationUser> userManager { get; set; }
Which as far as I understand it points the identity code to use the right DbContext - I looked at doing this in reverse in my AccountController but can't fathom it out.
I basically just want to be able to use my own code that grabs my own data from within the Identity controllers to help pass extra data etc through to the views.
I might be wrong but most probably postmgr field is not initialized from constructor and that is why you have this error.
Explanation:
By default Asp will try to create controller instance by constructor without parameters. If Asp can't find constructor without parameters it will try to call constructor with parameters, but to make it possible you have to configure IoC in your app. As your controler has constructor without parameters it will be selected by Asp. So all 3 fields are empty.
But in properties SignInManager and UserManager you try to take value from field or from OwinContext. As field is empty your code will take value from OwinContext. OwinContext is quite complex and smart tool that create its context automatically based on configuration provided in Startup.Auth.cs file or any other file under App_Start folder.
I think I have figured it out - added the following to my NinjectControllerFactory :
ninjectKernel.Bind<IAuthenticationManager>().ToMethod(c => HttpContext.Current.GetOwinContext().Authentication); //.InRequestScope();
ninjectKernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>();
ninjectKernel.Bind<UserManager<ApplicationUser>>().ToSelf();
ninjectKernel.Bind<IRoleStore<IdentityRole, string>>().To<RoleStore<IdentityRole, string, IdentityUserRole>>();
ninjectKernel.Bind<RoleManager<IdentityRole>>().ToSelf();
And changed my constructor to :
public AccountController(PostageManager _postmgr)
{
postmgr = _postmgr;
}

MVC user Authentication using Web API

I have built a WebAPI for user login, the webAPI can generate Access Token, if the user provided correct UserName and password. My Question is how I can pass user role information to the MVC application also.
For example,
I have a MVC app controller below, how can I pass the role 'Admin, UserEditor' from the Web API? I know I can use another WebAPI call to check user role, but it is not a good idea to do it.
[Authorized("Admin,UserEditor")]
ActionResult EditUser(int? Id)
{
........
}
You can read role information from claims.
Step-1 Create Role-s
I created it seed, but your choice may be different.
public static class MyDbInitializer
{
public static void Seed(this ModelBuilder builder)
{
Guid adminRoleId = Guid.Parse("90a5d1bb-2cf0-4014-9f1a-2d9f644a2e22");
builder.Entity<IdentityRole<Guid>>().HasData(
new IdentityRole<Guid>
{
Id = adminRoleId,
Name = RoleIdentifier.admin,
NormalizedName = RoleIdentifier.admin.ToUpper(CultureInfo.GetCultureInfo("en-GB"))
});
}
}
Step-2 Claims
public static class RoleIdentifier
{
public const string admin = "admin";
public const string user = "user";
}
public static class JwtClaimIdentifier
{
public const string UserId = "user_id";
public const string UserName = "user_name";
public const string Role = "role";
}
Where you generate tokens, add the role name to the claims information.
...
... string role = await _userService.GetRole(userId);
... identity.FindFirst(JwtClaimIdentifier.Role)
Step-3 Add authorize att. to controllers.
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = RoleIdentifier.admin)]
public class FooController
{
}
When the logged in user wants to access this action, the possession of this role will match and access claims.
You need to use 2 authentication mechanisms (Bearer Tokens, and Cookies) because your are securing Web API end points using tokens and MVC 5 controllers using Cookies. I recommend you to check VS 2013 Web template with MVC core dependency selected. It contains all the code needed at your case. Inside the GrantResourceOwnerCredentials method you will find something similar to the below:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
Notice how there are oAuthIdentity for Web API, and cookiesIdentity for MVC application.

What Type (class) do i use for a property in my POCO for Asp.net Identy User

I have a codefirst POCO, and i want to specify a LastEditUser from my current ASP.NET IDENTITY user. I tried type ApplicationUser that gets generated with the new project. but it just saves as null.
Here is my current Attempt
public class SomeClass
{
public string SomeProperty { get; set; }
public ApplicationUser LastEditMember { get; set; }
}
And here is how i try to save it in my controller.
string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
instannceOfSomeClass.LastEditMember = currentUser;
After loading this again. the LastEditMember property is null.
I would suggest using the UserManager class to get the user object instead of working with the DbContext object. You can use UserManager.FindByIdAsync(currentUserId) to get the user. Also I am considering that this code is hit only after a user logs into the application else the currentUserId will be null

Resources