14

I am new to ASP.NET core itself. However, I am creating WebAPIs in ASP.NET Core 2.0. I have configured JWT Bearer Token based authentication. Below is my Controller which return token.

    [AllowAnonymous]
[Route("api/[controller]")]
public class TokenController : Controller
{
    private readonly UserManager<UserEntity> userManager;
    private readonly SignInManager<UserEntity> signInManager;

    public TokenController(UserManager<UserEntity> userManager, SignInManager<UserEntity> signInManager)
    {
        this.userManager = userManager;
        this.signInManager = signInManager;
    }

    // GET: api/values
    [HttpGet]
    public async Task<IActionResult> Get(string username, string password, string grant_type)
    {
        {
            var user = await userManager.FindByEmailAsync(username);

            if (user != null)
            {
                var result =await signInManager.CheckPasswordSignInAsync(user, password, false);
                if (result.Succeeded)
                {

                    var claims = new[]
                    {
                        new Claim( JwtRegisteredClaimNames.Sub, username),
                        new Claim( JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                        new Claim( JwtRegisteredClaimNames.GivenName, "SomeUserID")
                    };

                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secretesecretesecretesecretesecretesecrete"));
                    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                    var token = new JwtSecurityToken( issuer: "test",
                                                     audience: "test",
                                                     claims: claims,
                                                      expires: DateTime.Now.AddDays(15),
                                                      signingCredentials: creds);

                    return Ok(new { access_token = new JwtSecurityTokenHandler().WriteToken(token), expires_on=DateTime.Now.AddDays(15) });

                }
            }
        }

        return BadRequest("Could not create token");
    }


}

But when calling ValuesController API which is decorated with [Authorize] attributes. I am getting User.Identity.Name is empty. I am not getting any information about user. I am not sure, My token controller is correctly written. As long as it is protecting my ValuesController, I assume, it is correct. However, I might be missing something. Please help.

Note: I am developing using Visual Studio 2017 with Mac Community addition

Nps
  • 1,568
  • 4
  • 18
  • 37

3 Answers3

31

Yes, you need to specify the claim for the unique name which is translated into the user.identity.name:

new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
Stoyan Dimov
  • 4,440
  • 2
  • 24
  • 38
Shawn Wildermuth
  • 6,838
  • 3
  • 21
  • 28
23

I've also been having this problem with ASP.Net Core 2, and I'm really surprised no one's discovered the other cause of this problem.

When my webapp is deployed to IIS, "User.Identity.Name" always returns null. The IIS site has anonymous access disabled, and windows authentication is enabled.

BUT.

I didn't realise that my ASP.Net Core 2 has a "launchSettings.json" file, quietly hidden under the Properties folder, and in there, there's also some iisSettings, and in here "windowsAuthentication" was, strangely, set as false by default.

enter image description here

Changing "windowsAuthentication" to true, and "anonymousAuthentication" to false solved the problem for me.

After doing this, "User.Identity.Name" did finally contain the correct username.

But what the heck is this setting ? Why would this get priority over the actual settings we've setup in IIS Manager ?!

Mike Gledhill
  • 23,658
  • 6
  • 133
  • 143
  • 5
    Why was this voted down ? This is exactly relevant to the question asked, and this answer hasn't been presented anywhere else. Isn't that the point of StackOverflow ? – Mike Gledhill Sep 04 '18 at 12:45
  • 1
    Maybe it didn't solve the problem for everybody, like mine is still broken after trying your suggested fix. – jwize Jan 17 '19 at 17:59
  • Because it didn't solve the problem for everybody doesn't mean it isn't a valid cause. I don't think this deserves the downvotes. I'd disagree with Mike's argument, though—settings in `launchSettings.json`should _always_ override settings on the IIS server. How else do you get to set general conditions and allow some applications to override them? So, it's a good answer to the original question, but the last paragraph is unnecessary. – Auspex Sep 05 '19 at 12:46
  • 1
    @MikeGledhill In my case as well, it worked perfectly. Stackoverflow must ask for a comment before downvotting.. – Sandeep Thomas May 06 '20 at 12:08
  • That finger is disturbing somehow – Maya Sep 08 '20 at 12:08
6

Had this problem too (Core 3.1) using the "DefaultIdentity" (Individual User Accounts). User.Identity.Name is null, User.Identity.IsAuthenticated = true. By using httpContextAccessor you can get the userId an with that id you can find the user and the UserName. In your controller add

using System.Security.Claims;
...
private readonly IHttpContextAccessor _httpContextAccessor;
public MyController(MyContext context, IHttpContextAccessor httpContextAccessor)
{
  _context = context;
  _httpContextAccessor = httpContextAccessor;
}

// Any method username needed
[HttpGet("{id}")]
public async Task<ActionResult<MyInfo>> GetMyInfo(int id)
{
  var userId = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
  var user = _context.AspNetUsers.Find(userId);
  var userName = user.UserName;
  ...
}

In the Startup.cs add the following line:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Gerard
  • 2,311
  • 1
  • 23
  • 35