forked from AcaMate/AcaMate_API
194 lines
7.0 KiB
C#
194 lines
7.0 KiB
C#
using AcaMate.Common.Data;
|
|
using AcaMate.Common.Token;
|
|
using AcaMate.Common.Models;
|
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System.Linq.Expressions;
|
|
using System.Security.Claims;
|
|
using AcaMate.V1.Models;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using Microsoft.VisualBasic;
|
|
|
|
namespace AcaMate.V1.Services;
|
|
|
|
public interface IRepositoryService
|
|
{
|
|
Task<bool> SaveData<T, K>(T entity, Expression<Func<T, K>> key) where T : class;
|
|
Task<ValidateToken> ValidateToken(string token, string refresh);
|
|
Task<bool> SaveDataFK<T>(T entity) where T : class;
|
|
}
|
|
|
|
public class RepositoryService: IRepositoryService
|
|
{
|
|
private readonly AppDbContext _dbContext;
|
|
private readonly ILogger<RepositoryService> _logger;
|
|
private readonly JwtTokenService _jwtTokenService;
|
|
|
|
public RepositoryService(AppDbContext dbContext, ILogger<RepositoryService> logger, JwtTokenService jwtTokenService)
|
|
{
|
|
_dbContext = dbContext;
|
|
_logger = logger;
|
|
_jwtTokenService = jwtTokenService;
|
|
}
|
|
|
|
public async Task<bool> SaveData<T, K> (T entity, Expression<Func<T, K>> key) where T : class
|
|
{
|
|
try
|
|
{
|
|
var value = key.Compile()(entity);
|
|
|
|
// x 라 함은 Expression 으로 생성되는 트리에서 T 타입으의 매개변수를 지칭함
|
|
var parameter = Expression.Parameter(typeof(T), "x");
|
|
|
|
var invokedExpr = Expression.Invoke(key, parameter);
|
|
var constantExpr = Expression.Constant(value, key.Body.Type);
|
|
var equalsExpr = Expression.Equal(invokedExpr, constantExpr);
|
|
|
|
var predicate = Expression.Lambda<Func<T, bool>>(equalsExpr, parameter);
|
|
|
|
var dbSet = _dbContext.Set<T>();
|
|
|
|
var entityData = await dbSet.FirstOrDefaultAsync(predicate);
|
|
|
|
if (entityData != null)
|
|
{
|
|
_logger.LogInformation($"[{typeof(T)}] 해당 PK 존재 [{value}]: 계속");
|
|
var entry = _dbContext.Entry(entityData);
|
|
entry.CurrentValues.SetValues(entity);
|
|
if (entry.Properties.Any(p => p.IsModified))
|
|
{
|
|
_logger.LogInformation($"[{typeof(T)}] 변경사항 존재: 계속");
|
|
}
|
|
else
|
|
{
|
|
_logger.LogInformation($"[{typeof(T)}] 변경사항 없음: 종료");
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_logger.LogInformation($"[{typeof(T)}] 처음등록");
|
|
dbSet.Add(entity);
|
|
}
|
|
|
|
await _dbContext.SaveChangesAsync();
|
|
_logger.LogInformation($"[{typeof(T)}] DB 저장 완료: 종료");
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogInformation($"[{typeof(T)}] 알 수 없는 오류: 종료 {ex}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//토큰 태울때는 인코딩 된 걸로 태워야지 원본꺼 태우면 데이터에 손상옵니다.
|
|
/// <summary>
|
|
/// 실제로 엑세스 토큰과 리프레시 토큰으로 접근 하기 위한 메서드
|
|
/// </summary>
|
|
public async Task<ValidateToken> ValidateToken(string token, string refresh)
|
|
{
|
|
var principalToken = _jwtTokenService.ValidateToken(token);
|
|
if (principalToken != null)
|
|
{
|
|
var uid = principalToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty;
|
|
_logger.LogInformation($"토큰 변환 - {uid}");
|
|
return new ValidateToken
|
|
{
|
|
token = token,
|
|
refresh = refresh,
|
|
uid = uid
|
|
};
|
|
}
|
|
else
|
|
{
|
|
_logger.LogInformation("엑세스 토큰 만료");
|
|
var refreshToken = await _dbContext.RefreshTokens
|
|
.FirstOrDefaultAsync(t => t.refresh_token == refresh);
|
|
if (refreshToken == null)
|
|
throw new TokenException("입력 받은 토큰 자체의 문제");
|
|
|
|
var uid = refreshToken.uid;
|
|
|
|
if (refreshToken.revoke_Date < DateTime.Now)
|
|
throw new RefreshRevokeException("리프레시 토큰 해지");
|
|
|
|
if (refreshToken.expire_date > DateTime.Now)
|
|
{
|
|
_logger.LogInformation($"인증 완료 리프레시 : {uid}");
|
|
var access = _jwtTokenService.GenerateJwtToken(uid);
|
|
|
|
return new ValidateToken
|
|
{
|
|
token = access,
|
|
refresh = refreshToken.refresh_token,
|
|
uid = uid
|
|
};
|
|
}
|
|
else
|
|
{
|
|
refreshToken = _jwtTokenService.GenerateRefreshToken(uid);
|
|
_logger.LogInformation("리프레시 토큰 만료");
|
|
await SaveData<RefreshToken, string>(refreshToken, rt => rt.uid);
|
|
return new ValidateToken
|
|
{
|
|
token = token,
|
|
refresh = refreshToken.refresh_token,
|
|
uid = uid
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
// public async Task SaveData<T, T1>(T pushCabinet)
|
|
// {
|
|
// throw new NotImplementedException();
|
|
// }
|
|
|
|
|
|
public async Task<bool> SaveDataFK<T>(T entity) where T : class
|
|
{
|
|
try
|
|
{
|
|
// EF Core 메타데이터를 통해 엔티티 T의 기본 키 속성 정보를 가져옴
|
|
var keyProperties = _dbContext.Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties;
|
|
|
|
// 각 키 속성에 대해, entity에서 실제 키 값을 추출
|
|
var keyValues = keyProperties
|
|
.Select(p => typeof(T).GetProperty(p.Name).GetValue(entity))
|
|
.ToArray();
|
|
|
|
// 기본 키 값을 이용해서 기존 엔티티를 찾음 (복합 키도 자동으로 처리됨)
|
|
var existingEntity = await _dbContext.Set<T>().FindAsync(keyValues);
|
|
|
|
if (existingEntity != null)
|
|
{
|
|
_logger.LogInformation($"[{typeof(T)}] 기존 데이터 발견: 기본 키 값({string.Join(", ", keyValues)})");
|
|
// 기존 엔티티를 업데이트: 새 entity의 값으로 교체
|
|
_dbContext.Entry(existingEntity).CurrentValues.SetValues(entity);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogInformation($"[{typeof(T)}] 신규 데이터 등록: 기본 키 값({string.Join(", ", keyValues)})");
|
|
// 데이터가 없으면 새 엔티티 추가
|
|
_dbContext.Set<T>().Add(entity);
|
|
}
|
|
|
|
// 변경 사항 저장
|
|
await _dbContext.SaveChangesAsync();
|
|
_logger.LogInformation($"[{typeof(T)}] DB 저장 완료");
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError($"[{typeof(T)}] 저장 중 오류 발생: {ex}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
} |