how do I pass and Object in a JWT claim in Asp.NetCore WebApi e.g lets say I want to pass an object of Gender with an ID and Name.
private IActionResult GenerateJwtToken(string email, ApplicationUser user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Id.ToString()),
new Claim(ClaimTypes.Email, user.Email.ToString()),
new Claim(ClaimTypes.GivenName, user.FirstName.ToString()),
new Claim(ClaimTypes.UserData, user.LastName.ToString()),
new Claim(ClaimTypes.StreetAddress, user.Address.ToString()),
new Claim(ClaimTypes.DateOfBirth, user.DateOfBirth.ToString()),
new Claim(ClaimTypes.Rsa, user.FileName.ToString()),
new Claim(ClaimTypes.Gender, user.Sex.ToString()),
new Claim(ClaimTypes.Country, user.Country.ToString()),
new Claim(ClaimTypes.StateOrProvince, user.state.ToString()),
new Claim(ClaimTypes.Locality, user.LGA.ToString()),
new Claim(ClaimTypes.Hash, user.HairColor.ToString()),
new Claim(ClaimTypes.Sid, user.GenoType.Name.ToString()),
new Claim(ClaimTypes.Spn, user.BloodGroup.ToString()),
new Claim(ClaimTypes.System, user.Religion.ToString()),
new Claim(ClaimTypes.NameIdentifier, user.NKName.ToString()),
new Claim(ClaimTypes.OtherPhone, user.NKPhoneNumber.ToString()),
new Claim(ClaimTypes.SerialNumber, user.NKAddress.ToString()),
new Claim(ClaimTypes.GroupSid, user.NKRelationship.ToString()),
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return Ok(new{ token = tokenString });
}
Please if there is any better way of getting the current logged in user details aside from Claims, i would love to know about it. Thanks in advance
[HttpGet("/api/profile")]
public IActionResult Index()
{
var claimIdentity = this.User.Identity as ClaimsIdentity;
IEnumerable<Claim> claims = claimIdentity.Claims;
var model = new IndexViewModel
{
Id = claimIdentity.FindFirst(ClaimTypes.Name).Value,
Email = claimIdentity.FindFirst(ClaimTypes.Email).Value,
FirstName = claimIdentity.FindFirst(ClaimTypes.GivenName).Value,
LastName = claimIdentity.FindFirst(ClaimTypes.UserData).Value,
Address = claimIdentity.FindFirst(ClaimTypes.StreetAddress).Value,
DateOfBirth = claimIdentity.FindFirst(ClaimTypes.DateOfBirth).Value,
FileName = claimIdentity.FindFirst(ClaimTypes.Rsa)?.Value,
};
return Ok(model);
}
Since the claim can store only string values, you need to represent your objects as a string. For example, you can use Json.net
nuget package to serialize/deserialize your object to/from a json
format. It could be like that:
string genderStr = JsonConvert.SerializeObject(gender);
// {
// "Id": 1,
// "Name": "Male"
// }
Gender genderObj = JsonConvert.DeserializeObject<Gender>(genderStr);
if there is any better way of getting the current logged in user details aside from Claims
As I see your claims are stored in the token and it is OK to get it from claims like you do. Another option could be to store user details in some storage e.g. DB. In this case you would need to take user id from claims and get all details from your storage.
Both options are worth considering. Using the first option you will increase the token size and decrease amount of DB requests. Using the second option you will decrease the token size and increase amount of DB requests.