AcaMate_API/Program/Common/JWTToken/JwtTokenService.cs

116 lines
3.8 KiB
C#

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Collections.Generic;
using AcaMate.Common.Models;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using System.Security.Cryptography;
namespace AcaMate.Common.Token;
public class JwtTokenService
{
private readonly JwtSettings _jwtSettings;
private readonly ILogger<JwtTokenService> _logger;
public JwtTokenService(IOptions<JwtSettings> jwtSettings, ILogger<JwtTokenService> logger)
{
_jwtSettings = jwtSettings.Value;
_logger = logger;
}
public string GenerateJwtToken(string uid)//, string role)
{
// 1. 클레임(Claim) 설정 - 필요에 따라 추가 정보도 포함
var claims = new List<Claim>
{
// 토큰 주체(sub) 생성을 위해 값으로 uid를 사용함 : 토큰이 대표하는 고유 식별자
new Claim(JwtRegisteredClaimNames.Sub, uid),
// Jti 는 토큰 식별자로 토큰의 고유 ID 이다.
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
// jwt 토큰이 가지는 권한
// new Claim(ClaimTypes.Role, role),
// 추가 클레임 예: new Claim(ClaimTypes.Role, "Admin")
};
// 2. 비밀 키와 SigningCredentials 생성
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
// 3. 토큰 생성 (Issuer, Audience, 만료 시간, 클레임, 서명 정보 포함)
var token = new JwtSecurityToken(
issuer: _jwtSettings.Issuer,
audience: _jwtSettings.Audience,
claims: claims,
expires: DateTime.Now.AddMinutes(_jwtSettings.ExpiryMinutes),
signingCredentials: credentials
);
// 4. 토큰 객체를 문자열로 변환하여 반환
return new JwtSecurityTokenHandler().WriteToken(token);
}
public RefreshToken GenerateRefreshToken(string uid)
{
var randomNumber = new byte[32]; // 256비트
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randomNumber);
}
// return Convert.ToBase64String(randomNumber);
return new RefreshToken()
{
uid = uid,
refresh_token = Convert.ToBase64String(randomNumber),
create_Date = DateTime.UtcNow,
expire_date = DateTime.UtcNow.AddDays(_jwtSettings.RefreshTokenExpiryDays)
};
}
public ClaimsPrincipal ValidateToken(string token)
{
if (string.IsNullOrWhiteSpace(token)) return null;
var tokenHandler = new JwtSecurityTokenHandler();
try
{
var key = Encoding.UTF8.GetBytes(_jwtSettings.SecretKey);
var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = true,
ValidIssuer = _jwtSettings.Issuer,
ValidateAudience = true,
ValidAudience = _jwtSettings.Audience,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(_jwtSettings.ClockSkewMinutes)
};
var principal = tokenHandler.ValidateToken(token, validationParameters, out var securityToken);
return principal;
}
catch (Exception e)
{
Console.WriteLine($"검증 실패 {e}");
return null;
}
}
}