[] JWT 생성 + 확인 로직 구현 중 & 회원가입, 로그아웃 API 구현 중

This commit is contained in:
김선규 2025-02-24 17:54:38 +09:00
parent 55f40e56cf
commit f1a901820f
5 changed files with 133 additions and 27 deletions

View File

@ -72,7 +72,9 @@ builder.Services.AddAuthentication(options =>
// JWT 설정부 끝
builder.Services.AddControllers();
// 여기다가 API 있는 컨트롤러들 AddScoped 하면 되는건가?
builder.Services.AddScoped<AcaMate.Common.Token.JwtTokenService>();
// builder.Services.AddScoped<UserService>(); //
// builder.Services.AddScoped<UserController>();

View File

@ -6,6 +6,9 @@ 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;
@ -30,8 +33,9 @@ public class JwtTokenService
// Jti 는 토큰 식별자로 토큰의 고유 ID 이다.
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
// jwt 토큰이 가지는 권한
new Claim(ClaimTypes.Role, role)
new Claim(ClaimTypes.Role, role),
// 추가 클레임 예: new Claim(ClaimTypes.Role, "Admin")
new Claim(ClaimTypes.NameIdentifier, uid)
};
// 2. 비밀 키와 SigningCredentials 생성
@ -43,7 +47,7 @@ public class JwtTokenService
issuer: _jwtSettings.Issuer,
audience: _jwtSettings.Audience,
claims: claims,
expires: DateTime.UtcNow.AddMinutes(_jwtSettings.ExpiryMinutes),
expires: DateTime.Now.AddMinutes(_jwtSettings.ExpiryMinutes),
signingCredentials: credentials
);
@ -63,10 +67,46 @@ public class JwtTokenService
return new RefreshToken()
{
uid = uid,
token = Convert.ToBase64String(randomNumber),
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;
}
}
}

View File

@ -12,16 +12,34 @@ public class JwtSettings
public int ClockSkewMinutes { get; set; }
public int RefreshTokenExpiryDays { get; set; }
}
[Table(("refresh_token"))]
[Table("refresh_token")]
public class RefreshToken
{
[Key]
[Required(ErrorMessage = "필수 항목 누락")]
public string uid { get; set; }
public string token { get; set; }
public string refresh_token { get; set; }
public DateTime create_Date { get; set; }
public DateTime expire_date { get; set; }
// 이건 로그아웃시에 폐기 시킬예정이니 그떄 변경하는걸로 합시다.
public DateTime? revoke_Date { get; set; }
}
}
/*
"""
1. .
2. DB에 .
3. .
4. .
5. (1) .
6. (2) .
7. .
8. .
9. .
10. 2 .
"""
*/

View File

@ -1,3 +1,6 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using AcaMate.Common.Data;
using AcaMate.Common.Models;
using AcaMate.V1.Models;
@ -9,6 +12,7 @@ using AcaMate.Common.Token;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore.Query;
using MySqlConnector;
using System.Linq;
namespace AcaMate.V1.Controllers;
@ -235,8 +239,49 @@ public class UserController : ControllerBase
}
// TO-DO: jwt 토큰 만들어서 여기서 보내는 작업을 해야 함
var token = _jwtTokenService.GenerateJwtToken(uid, "admin");
var refreshToken = _jwtTokenService.GenerateRefreshToken(uid);
await SaveData<RefreshToken, string>(refreshToken, rt => rt.uid);
/* */
var principalToken = _jwtTokenService.ValidateToken(token);
if (principalToken != null)
{
var jti = principalToken.FindFirst(JwtRegisteredClaimNames.Jti)?.Value;
var sub = principalToken.FindFirst(JwtRegisteredClaimNames.Sub)?.Value;
var id = principalToken.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var id2 = principalToken.FindFirst(JwtRegisteredClaimNames.Sub)?.Value;
// var check = principalToken.FindFirst("sub")?.Value;
_logger.LogInformation($"토큰? - {jti}");
_logger.LogInformation($"토큰? - {sub}");
_logger.LogInformation($"토큰? - {id}");
// TODO: 도대체 토큰 이거 sub확인이 왜 안되는걸까.?
}
else
{
_logger.LogInformation("dd");
}
/* */
return Ok($"회원가입 : {uid}");
var result = new APIResponseStatus<dynamic>()
{
status = new Status()
{
code = "000",
message = "정상"
},
data = new
{
uid = uid,
accessToken = token,
refreshToken = refreshToken.refresh_token
}
};
return Ok(result.JsonToString());
}
private async Task<bool> SaveData<T, K> (T entity, Expression<Func<T, K>> key) where T : class
{
@ -287,5 +332,26 @@ public class UserController : ControllerBase
}
}
[HttpGet("logout")]
[CustomOperation("로그아웃", "사용자 로그아웃", "사용자")]
public async Task<IActionResult> LogOut(string token, string refresh)//([FromBody] UserAll request)
{
var principalToken = _jwtTokenService.ValidateToken(token);
if (principalToken != null)
{
// var uid = principalToken.FindFirst(JwtRegisteredClaimNames.Jti)?.Value;
var uid = principalToken.FindFirst("sub")?.Value;
_logger.LogInformation($"토큰? - {uid}");
}
else
{
_logger.LogInformation("dd");
}
return Ok("로그아웃");
}
}

View File

@ -79,26 +79,6 @@ public class Permission
public bool market_email_yn {get; set;}
}
[Table("token")]
public class Token
{
[Key]
[Required(ErrorMessage = "필수 항목 누락")]
public string uid { get; set; }
[Required(ErrorMessage = "필수 항목 누락")]
public string refresh_token { get; set; }
[Required(ErrorMessage = "필수 항목 누락")]
public DateTime create_date { get; set; }
[Required(ErrorMessage = "필수 항목 누락")]
public DateTime expires_date { get; set; }
[Required(ErrorMessage = "필수 항목 누락")]
public DateTime revoke_date { get; set; }
}
[Table("location")]
public class Location