jbraun
jbraun

Reputation: 1648

ASP.NET Core Identity - get current user

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;

Upvotes: 147

Views: 283022

Answers (7)

Gerardo Grignoli
Gerardo Grignoli

Reputation: 15217

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;
    }

Upvotes: 224

Rokive
Rokive

Reputation: 825

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);
}

Upvotes: 7

Dblock247
Dblock247

Reputation: 6755

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;
}

Upvotes: 6

Marko
Marko

Reputation: 41

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).

Upvotes: 4

Joel Palmer
Joel Palmer

Reputation: 143

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();

Upvotes: 8

Bhail
Bhail

Reputation: 740

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; }

Upvotes: 7

Greg Gum
Greg Gum

Reputation: 38109

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.

Upvotes: 52

Related Questions