2

I create update user in my App and then I test my app in Postman and in Web App but create different result. When I tried this code in postman it work but web app doesn't work (Code in ASP.NET CORE 2.0, Web App using Angular 5)

[HttpPut("{id}")]
    public async Task<IActionResult> UpdateUser(int id, [FromBody] UserForUpdateDto userDto) {
        if(!ModelState.IsValid)
            return BadRequest(ModelState);

        var currentUserId = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);
        var userFromRepo = await _orgRepo.GetUser(id);
        if(userFromRepo == null) 
            return NotFound($"User not found with id: {id}");
        if (currentUserId != userFromRepo.Id)
            return Unauthorized();

        _mapper.Map<UserForUpdateDto, User>(userDto, userFromRepo);

        if (await _orgRepo.SaveAll())
            return NoContent();

        throw new Exception($"Updating user {id} failed on save");
    }

From the WebApp it produce error: "Object reference not set to an instance of an object."

When I debug the app it seems the line caused that

var currentUserId = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);

I check and it produce null.

Any idea where the User was set ?

My Login Controller:

[HttpPost("login")]
    public async Task<IActionResult> Login([FromBody]UserForLoginDto userForLoginDto)
    {
        var userFromRepo = await _repo.Login(userForLoginDto.Username.ToLower(), userForLoginDto.Password);

        if (userFromRepo == null)
            return Unauthorized();

        // generate token
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_config.GetSection("AppSettings:Token").Value);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.NameIdentifier, userFromRepo.Id.ToString()),
                new Claim(ClaimTypes.Name, userFromRepo.Username),
                new Claim(ClaimTypes.Role, "RegisteredUsers")
            }),
            Expires = DateTime.Now.AddDays(3),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
                SecurityAlgorithms.HmacSha512Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        var tokenString = tokenHandler.WriteToken(token);

        var user = _mapper.Map<UserForDetailDto>(userFromRepo);
        return Ok(new { tokenString, user });

    }
2
  • 1
    “When I tried this code in postman it work but web app doesn't work” – Then check exactly what makes the request in the web app different to the one you did in postman. Commented Apr 23, 2018 at 7:17
  • If your API is using a JWT token in the Authorization header then the user id will be in the JwtClaimTypes.Subject claim (sub). Commented Apr 23, 2018 at 7:22

1 Answer 1

3

If an api method contains [Authorize] then an authorization header is sent along with the request. If no header is sent then you have no user.

[HttpPut("{id}")]
[Authorize(AuthenticationSchemes = "Bearer")]
public async Task<IActionResult> UpdateUser(int id, [FromBody] UserForUpdateDto userDto) 
   {    
       var sub = User.GetSubjectId();   // Subject Id is the user id
    }
Sign up to request clarification or add additional context in comments.

3 Comments

While this is probably a good idea in general (to protect the route), note that the authentication middleware will still authenticate the user if a token is provided regardless of whether the route requires authorization or not.
@poke Have a link to that? I have never seen a method authorize automatically where it wasn't specified in at either the controller level or the method level. I would love to get some more information on that.
The authentication middleware that you add with app.UseAuthentication() will attempt to authenticate with the default authentication scheme. So when JwtBearer is your default scheme, the user will be resolved whether your route is authenticated or not. That’s also how the normal ASP.NET Core Identity (which is essentially just CookieAuth) is able to show the currently logged in user without requiring authorized routes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.