Problem
I’d like to get a hold of the current user so that I may obtain information such as their email address. However, I am unable to do so on ASP.NET Core. My code is as follows:
In the constructor of the controller, HttpContext is practically null. It’s not a good idea to include a user in every action. I’d like to receive the user’s data only once and save it to ViewData;
public DashboardController()
{
var user = HttpContext.User.GetUserId();
}
Asked by Mehran Hafizi
Solution #1
User.FindFirst(ClaimTypes.NameIdentifier).Value
EDIT for constructor
Below code works:
public Controller(IHttpContextAccessor httpContextAccessor)
{
var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value
}
Edit for RTM
IHttpContextAccessor should be registered:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
}
Answered by adem caglin
Solution #2
I tested a simple method that works.
private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
var user = await _userManager.GetUserAsync(HttpContext.User);
Then you can see all of the variables’ properties, such as user. Email. I’m hoping this will be of assistance to someone.
Edit:
It appears to be a simple thing, but it’s a little more tricky in ASP.NET Core due to the various sorts of authentication systems. Because some folks are receiving null, I updated.
For JWT Authentication (ASP.NET Core v3.0.0-preview7), use the following code:
var email = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
var user = await _userManager.FindByEmailAsync(email);
Answered by Ahmad
Solution #3
I must admit that the fact that HttpContext is null inside the constructor startled me. I’m sure it’s for the sake of performance. I’ve validated that injecting IPrincipal into the constructor as indicated below works. It effectively accomplishes the same task as the acceptable solution, but in a more user-friendly manner.
If you’re seeking for a solution to the generic query “How do I retrieve the current user?” you may simply access User from Controller. User. However, you can only do this inside action methods (I suppose for performance reasons and because controllers don’t only run with HttpContexts).
However, if you need it in the constructor (as the OP did) or you need to create other injectable objects that require the current user, the following technique is preferable:
IIdentity and IPrincipal are the first two people you should meet.
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
The user and username are represented by IPrincipal and IIdentity. If the word ‘Principal’ gives you the creeps, look it up on Wikipedia.
It’s crucial to understand whether you acquire it from IHttpContextAccessor or not. ControllerBase, HttpContext.User User or ControllerBase are the two options. You obtain an object that is guaranteed to be a ClaimsPrincipal object that implements IPrincipal when you use HttpContext.User.
There isn’t another type of User that ASP.NET uses for User right now (but it doesn’t rule out the possibility of something else implementing IPrincipal).
If you wish to inject something that depends on ‘the current user name,’ you should inject IPrincipal, not IHttpContextAccessor.
Important: Don’t waste time injecting IPrincipal into your controller or action method; it’s redundant because User is already available.
In startup.cs:
// Inject IPrincipal
services.AddHttpContextAccessor();
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Then, in the DI object that requires the user, just inject IPrincipal to obtain the current user.
The most essential thing to remember here is that when performing unit tests, you don’t need to send in a HttpContext; instead, you only need to mimic anything that represents IPrincipal, which may simply be ClaimsPrincipal.
There’s one more item about which I’m not entirely certain. You must cast IPrincipal to ClaimsPrincipal to get access to the real claims from ClaimsPrincipal. This is fine because we know it’s of that type at runtime (because that’s what HttpContext.User is). Because I already know that any IPrincipal will be a ClaimsPrincipal, I prefer to do this in the constructor.
If you’re mocking, simply build a ClaimsPrincipal and pass it to whatever requires IPrincipal.
I’m not clear why there isn’t an interface for IClaimsPrincipal. I’m guessing Microsoft determined ClaimsPrincipal was merely a specialized ‘collection’ that didn’t require an interface.
Answered by Simon_Weaver
Solution #4
Have another means of getting the current user in Asp.NET Core – I believe I saw it on SO someplace.
// Stores UserManager
private readonly UserManager<ApplicationUser> _manager;
// Inject UserManager using dependency injection.
// Works only if you choose "Individual user accounts" during project creation.
public DemoController(UserManager<ApplicationUser> manager)
{
_manager = manager;
}
// You can also just take part after return and use it in async methods.
private async Task<ApplicationUser> GetCurrentUser()
{
return await _manager.GetUserAsync(HttpContext.User);
}
// Generic demo method.
public async Task DemoMethod()
{
var user = await GetCurrentUser();
string userEmail = user.Email; // Here you gets user email
string userId = user.Id;
}
That code is sent to DemoController, a controller. It won’t compile if you don’t use both awaits.
Answered by Hekkaryk
Solution #5
As of now (April 2017), it appears that the following works are in progress:
public string LoggedInUser => User.Identity.Name;
While inside a Controller, at the very least.
Answered by Grandizer
Post is based on https://stackoverflow.com/questions/36641338/how-to-get-current-user-in-asp-net-core