using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using System; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Text; using FamilyTreeAPI.Entities; using FamilyTreeAPI.Interface; namespace FamilyTreeAPI.Authorization; public class JwtUtils : IJwtUtils { private readonly AppSettings _appSettings; public JwtUtils(IOptions appSettings) { _appSettings = appSettings.Value; } public string GenerateJwtToken(UserDto user) { // generate token that is valid for 2 days var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(_appSettings.Secret); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()), new Claim("subject", user.Username), new Claim("firstName", user.FirstName + " " + user.LastName) { } //add more if we need it } ), Expires = DateTime.UtcNow.AddDays(2), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } // get back id and username. in subject public UserDto? ValidateJwtToken(string token) { if (token == null) return null; var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(_appSettings.Secret); try { tokenHandler.ValidateToken(token, new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false, // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later) ClockSkew = TimeSpan.Zero }, out SecurityToken validatedToken); var jwtToken = (JwtSecurityToken)validatedToken; // var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value); //old int userId = 0; string username = ""; string firstName = ""; Claim claim; for (int i = 0; i< jwtToken.Claims.Count(); i++) { claim = jwtToken.Claims.ElementAt(i); if (claim.Type == "id") { userId = int.Parse(claim.Value); } else if (claim.Type == "subject") { username = claim.Value; } else if (claim.Type == "firstName") { firstName = claim.Value; } if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(firstName) && userId > 0) { break; } } UserDto user = new UserDto(); user.Id = userId; user.Username = username; user.FirstName = firstName; // return user id from JWT token if validation successful return user; } catch { // return null if validation fails return null; } } }