Files
caliverse_server/UGQApiServer/JWT/TokenService.cs
2025-05-01 07:20:41 +09:00

150 lines
5.2 KiB
C#

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using UGQApiServer.Settings;
using UGQDatabase.Models;
namespace JwtRoleAuthentication.Services;
public class TokenService
{
readonly JWTSettings _jwtSettings;
public TokenService(IOptions<JWTSettings> settings)
{
_jwtSettings = settings.Value;
}
public string CreateToken(string userGuid, string nickname)
{
var token = CreateJwtToken(CreateClaims(userGuid, nickname));
var tokenHandler = new JwtSecurityTokenHandler();
return tokenHandler.WriteToken(token);
}
public string CreateAdminToken(string username, UGQAccountRole role)
{
var token = CreateJwtToken(CreateAdminClaims(username, role));
var tokenHandler = new JwtSecurityTokenHandler();
return tokenHandler.WriteToken(token);
}
public string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
public ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false, //you might want to validate the audience and issuer depending on your use case
ValidateIssuer = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret)),
ValidateLifetime = false //here we are saying that we don't care about the token's expiration date
};
var tokenHandler = new JwtSecurityTokenHandler();
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken);
var jwtSecurityToken = securityToken as JwtSecurityToken;
if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
throw new SecurityTokenException("Invalid token");
return principal;
}
public string GenerateAccessTokenFromRefreshToken(string refreshToken, string secret)
{
// Implement logic to generate a new access token from the refresh token
// Verify the refresh token and extract necessary information (e.g., user ID)
// Then generate a new access token
// For demonstration purposes, return a new token with an extended expiry
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Expires = DateTime.UtcNow.AddMinutes(15), // Extend expiration time
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
private JwtSecurityToken CreateJwtToken(List<Claim> claims)
{
var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret));
DateTime expiration = DateTime.UtcNow.AddMinutes(_jwtSettings.TokenValidityInMinutes);
return new(
_jwtSettings.ValidIssuer,
_jwtSettings.ValidAudience,
claims,
expires: expiration,
signingCredentials: new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256)
);
}
private List<Claim> CreateAdminClaims(string username, UGQAccountRole role)
{
try
{
var claims = new List<Claim>
{
// new Claim(JwtRegisteredClaimNames.Sub, jwtSub),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()),
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Role, role.ToString())
};
return claims;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
private List<Claim> CreateClaims(string userGuid, string nickname)
{
try
{
var claims = new List<Claim>
{
// new Claim(JwtRegisteredClaimNames.Sub, jwtSub),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()),
new Claim("Id", userGuid),
new Claim(ClaimTypes.Name, nickname),
// new Claim(ClaimTypes.Email, user.Email),
// new Claim(ClaimTypes.Role, user.Role.ToString())
};
return claims;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}