I wonder why the User.GetUserId(); returns 0 wherever it's used. What's the problem?
Actually, the IsAuthenticated = false for the User object.
I tried to test my application using Postman and Angular client applications. In both ways, the token is returned to the client successfully. In Postman I add the received token to the authorization field of the header like this:
Bearer <the token>
After sending the request to another action that contains User.GetUserId(); I get the same result. and User.GetUserId(); is still 0.
Configure method in Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors(x => x
.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin()
.AllowCredentials()
.WithOrigins("https://localhost:4200"));
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapFallbackToController("Index", "Fallback");
});
}
Login method in AccountController:
[HttpPost("login")]
public async Task<ActionResult<UserDto>> Login(LoginDto loginDto)
{
var user = await _userManager.Users
.Include(p => p.Photos)
.SingleOrDefaultAsync(x => x.UserName == loginDto.Username.ToLower());
if (user == null)
return Unauthorized("Invalid username");
var result = await _signInManager
.CheckPasswordSignInAsync(user, loginDto.Password, false);
if (!result.Succeeded)
return Unauthorized();
var token = await _tokenService.CreateToken(user);
var userDto = new UserDto
{
Username = user.UserName,
Token = token,
KnownAs = user.KnownAs,
Gender = user.Gender
};
var uId = User.GetUserId(); // it returns 0
return userDto;
}
TokenService.cs:
public class TokenService : ITokenService
{
private readonly SymmetricSecurityKey _key;
private readonly UserManager<AppUser> _userManager;
public TokenService(IConfiguration config, UserManager<AppUser> userManager)
{
_userManager = userManager;
_key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["TokenKey"]));
}
public async Task<string> CreateToken(AppUser user)
{
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.NameId, user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName.ToString())
};
var roles = await _userManager.GetRolesAsync(user);
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
var creds = new SigningCredentials(_key, SecurityAlgorithms.HmacSha512Signature);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.Now.AddDays(7),
SigningCredentials = creds
};
**//UPDATE**
var claimsPrincipal = new ClaimsPrincipal(identity);
_httpContextAccessor.HttpContext.User = new ClaimsPrincipal(identity);
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
}
UPDATE
after updating CreateTokenAsync() as you can see in the code I got the proper result from User in the login controller after calling CreateTokenAsync(). but after that when I called another endpoint the HttpContext.User became empty!
Having said that I injected IHttpContextAccessor into the class that CreateTokenAsync() is located.