132

To get the currently logged in user in MVC5, all we had to do was:

using Microsoft.AspNet.Identity;
[Authorize]
public IHttpActionResult DoSomething() {
    string currentUserId = User.Identity.GetUserId();
}

Now, with ASP.NET Core I thought this should work, but it throws an error.

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Http;

private readonly UserManager<ApplicationUser> _userManager;
[HttpPost]
[Authorize]
public async Task<IActionResult> StartSession() {
    var curUser = await _userManager.GetUserAsync(HttpContext.User);
}

Any ideas?

EDIT: Gerardo's response is on track but to get the actual "Id" of the user, this seems to work:

ClaimsPrincipal currentUser = this.User;
var currentUserID = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
jbraun
  • 1,498
  • 2
  • 11
  • 10
  • What is your question exactly? – Gerardo Grignoli Aug 03 '16 at 23:27
  • You only need the Id? I edited my answer to add how to get it using the more fancy _userManager.GetUserId(User) – Gerardo Grignoli Aug 03 '16 at 23:44
  • Yes, primarily I need the Id from AspNetUsers table, or from the session. currentUser.FindFirst(ClaimTypes.NameIdentifier).Value gives the Id using Claims. It works with UserManager too! Thank you Gerardo! Is one way more efficient than the other? – jbraun Aug 04 '16 at 22:02
  • UserManager internally does .FindFirst(ClaimTypes.NameIdentifier). So it is the same performance-wise. I prefer the usermanager encapsulation for ease of reading. On the other hand `.GetUserAsync()` is slower because it goes to the DB. – Gerardo Grignoli Aug 04 '16 at 22:07
  • I agree completely Gerardo. Thankyou ! – jbraun Aug 05 '16 at 01:40

7 Answers7

206

If your code is inside an MVC controller:

public class MyController : Microsoft.AspNetCore.Mvc.Controller

From the Controller base class, you can get the ClaimsPrincipal from the User property

System.Security.Claims.ClaimsPrincipal currentUser = this.User;

You can check the claims directly (without a round trip to the database):

bool isAdmin = currentUser.IsInRole("Admin");
var id = _userManager.GetUserId(User); // Get user id:

Other fields can be fetched from the database's User entity:

  1. Get the user manager using dependency injection

    private UserManager<ApplicationUser> _userManager;
    
    //class constructor
    public MyController(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }
    
  2. And use it:

    var user = await _userManager.GetUserAsync(User);
    var email = user.Email;
    

If your code is a service class, you can use dependency injection to get an IHttpContextAccessor that lets you get the User from the HttpContext.

    private IHttpContextAccessor _httpContextAccessor;

    public MyClass(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    private void DoSomething()
    {
        var user = _httpContextAccessor.Context?.User;
    }
Gerardo Grignoli
  • 14,058
  • 7
  • 57
  • 68
  • 7
    And if i'm in a service class and not in the controller, where i don't have the User Property? How to get the AppUser-Object of the authenticated user? – Kirsten Aug 10 '16 at 21:56
  • 19
    @Kirsten You can receive an `IHttpContextAccessor` with Dependency Injection and then get the `User` from the http context. Just add this param to the service class constructor: `IHttpContextAccessor contextAccessor`. Keep the accessor on a field `_contextAccessor` and then on the service methods get it from `_contextAccessor.HttpContext.User`. – Gerardo Grignoli Aug 11 '16 at 15:36
  • 6
    @Kirsten But doing this couples your service with ASP.NET Core, making it not usable on other kind of scenarios. This may be acceptable for you, or not. I will also consider passing exactly what you want to the service on the method call. – Gerardo Grignoli Aug 11 '16 at 15:39
  • 3
    You pushed me the right way: i built an IUserService with GetUser and IsAuthenticated. In my ASP.NET Core App I have an implementation userService which uses IHttpContextAccessor and the UserManager. So my userService is coupled to ASP.NET Core, my other services aren't. – Kirsten Aug 11 '16 at 16:06
  • 1
    Hi @GerardoGrignoli I'm wondering if User.IsInRole("") and _userManager.GetUserId(...) does not trigger the database? – alecardv May 11 '17 at 20:45
  • 2
    No, they don't go to the database. Checking the source, they don't use the UserStore. https://github.com/dotnet/corefx/blob/master/src/System.Security.Claims/src/System/Security/Claims/ClaimsPrincipal.cs#L536 https://github.com/aspnet/Identity/blob/5480aa182bad3fb3b729a0169d0462873331e306/src/Microsoft.AspNetCore.Identity/UserManager.cs#L345 – Gerardo Grignoli May 11 '17 at 21:59
  • If within a ViewComponent class, use UserClaimsPrincipal property instead. – maets Sep 20 '17 at 18:30
  • Isn't there a way to just get the authenticated user from the runtime subsystem? Something like AppDomain.CurrentUser or Thread.CurrentThread.CurrentUser... – Jens Mander Feb 26 '22 at 22:02
  • @JensMander use [Environment.UserName](https://learn.microsoft.com/en-us/dotnet/api/system.environment.username) to get the OS user (not the Asp.Net user) running the current thread. – Gerardo Grignoli Feb 27 '22 at 07:20
  • The _httpContextAccessor.Context has been changed to _httpContextAccessor.HttpContext. – Eric Conklin Mar 22 '22 at 20:52
49

If you are using Bearing Token Auth, the above samples do not return an Application User.

Instead, use this:

ClaimsPrincipal currentUser = this.User;
var currentUserName = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
ApplicationUser user = await _userManager.FindByNameAsync(currentUserName);

This works in apsnetcore 2.0. Have not tried in earlier versions.

Greg Gum
  • 33,478
  • 39
  • 162
  • 233
  • My tokens are being validated, but the principal and claims are not being set. This is happening in dotnet core 2.1 and 2.2 – ps2goat Jan 10 '19 at 16:05
  • @ps2goat, I would create a new question to address this, and include the code that is creating the token. – Greg Gum Jan 10 '19 at 18:34
  • 1
    I figured it out. We don't have a default scheme because we have 5 different schemes. I had to add a middleware to decode the token and assign the claims to the current user. I should probably write up a question and answer it for others, as there's very little content around my situation. – ps2goat Jan 10 '19 at 23:50
  • 2
    ClaimTypes.Name gets the username which what I was looking for instead of the Id. ClaimTypes.NameIdentifier gets the Id of the user. Just in case anyone sees this and is wondering how to get the username. Thanks for your answer Greg! – Matthew Zourelias Mar 27 '19 at 15:24
8

For context, I created a project using the ASP.NET Core 2 Web Application template. Then, select the Web Application (MVC) then hit the Change Authentication button and select Individual User accounts.

There is a lot of infrastructure built up for you from this template. Find the ManageController in the Controllers folder.

This ManageController class constructor requires this UserManager variable to populated:

private readonly UserManager<ApplicationUser> _userManager;

Then, take a look at the the [HttpPost] Index method in this class. They get the current user in this fashion:

var user = await _userManager.GetUserAsync(User);

As a bonus note, this is where you want to update any custom fields to the user Profile you've added to the AspNetUsers table. Add the fields to the view, then submit those values to the IndexViewModel which is then submitted to this Post method. I added this code after the default logic to set the email address and phone number:

user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.Address1 = model.Address1;
user.Address2 = model.Address2;
user.City = model.City;
user.State = model.State;
user.Zip = model.Zip;
user.Company = model.Company;
user.Country = model.Country;
user.SetDisplayName();
user.SetProfileID();

_dbContext.Attach(user).State = EntityState.Modified;
_dbContext.SaveChanges();
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
Joel Palmer
  • 143
  • 1
  • 7
7

In .NET Core 2.0 the user already exists as part of the underlying inherited controller. Just use the User as you would normally or pass across to any repository code.

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy = "TENANT")]
[HttpGet("issue-type-selection"), Produces("application/json")]
public async Task<IActionResult> IssueTypeSelection()
{
    try
    {
        return new ObjectResult(await _item.IssueTypeSelection(User));
    }
    catch (ExceptionNotFound)
    {
        Response.StatusCode = (int)HttpStatusCode.BadRequest;
        return Json(new
        {
            error = "invalid_grant",
            error_description = "Item Not Found"
        });
    }
}

This is where it inherits it from

#region Assembly Microsoft.AspNetCore.Mvc.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// C:\Users\BhailDa\.nuget\packages\microsoft.aspnetcore.mvc.core\2.0.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Core.dll
#endregion

using System;
using System.IO;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Routing;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Mvc
{
    //
    // Summary:
    //     A base class for an MVC controller without view support.
    [Controller]
    public abstract class ControllerBase
    {
        protected ControllerBase();

        //
        // Summary:
        //     Gets the System.Security.Claims.ClaimsPrincipal for user associated with the
        //     executing action.
        public ClaimsPrincipal User { get; }
Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
Bhail
  • 710
  • 8
  • 14
6

Just if any one is interested this worked for me. I have a custom Identity which uses int for a primary key so I overrode the GetUserAsync method

Override GetUserAsync

public override Task<User> GetUserAsync(ClaimsPrincipal principal)
{
    var userId = GetUserId(principal);
    return FindByNameAsync(userId);
}

Get Identity User

var user = await _userManager.GetUserAsync(User);

If you are using a regular Guid primary key you don't need to override GetUserAsync. This is all assuming that you token is configured correctly.

public async Task<string> GenerateTokenAsync(string email)
{
    var user = await _userManager.FindByEmailAsync(email);
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_tokenProviderOptions.SecretKey);

    var userRoles = await _userManager.GetRolesAsync(user);
    var roles = userRoles.Select(o => new Claim(ClaimTypes.Role, o));

    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString(CultureInfo.CurrentCulture)),
        new Claim(JwtRegisteredClaimNames.GivenName, user.FirstName),
        new Claim(JwtRegisteredClaimNames.FamilyName, user.LastName),
        new Claim(JwtRegisteredClaimNames.Email, user.Email),
    }
    .Union(roles);

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(claims),
        Expires = DateTime.UtcNow.AddHours(_tokenProviderOptions.Expires),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);

    return Task.FromResult(new JwtSecurityTokenHandler().WriteToken(token)).Result;
}
Dblock247
  • 6,167
  • 10
  • 44
  • 66
  • you don't need to overwrite the GetUserAsync method. you just need to create the generic UserManager property with your custom user class, like so; private readonly UserManager _userManager; then initialize it in Controller. this way, the GetUserAsync method returns the user in ApplicationUser class, which is your custom user class. – Emre Bener Feb 28 '23 at 07:21
5
private readonly UserManager<AppUser> _userManager;

 public AccountsController(UserManager<AppUser> userManager)
 {
            _userManager = userManager;
 }

[Authorize(Policy = "ApiUser")]
[HttpGet("api/accounts/GetProfile", Name = "GetProfile")]
public async Task<IActionResult> GetProfile()
{
   var userId = ((ClaimsIdentity)User.Identity).FindFirst("Id").Value;
   var user = await _userManager.FindByIdAsync(userId);

   ProfileUpdateModel model = new ProfileUpdateModel();
   model.Email = user.Email;
   model.FirstName = user.FirstName;
   model.LastName = user.LastName;
   model.PhoneNumber = user.PhoneNumber;

   return new OkObjectResult(model);
}
Rokive
  • 745
  • 9
  • 7
4

I have put something like this in my Controller class and it worked:

IdentityUser user = await userManager.FindByNameAsync(HttpContext.User.Identity.Name);

where userManager is an instance of Microsoft.AspNetCore.Identity.UserManager class (with all weird setup that goes with it).

Marko
  • 41
  • 3
  • 1
    Please provide an explanation about what you mean with `with all weird setup that goes with it`, as this would be unclear for new beginners. – Adnan Nov 05 '22 at 19:51