Skip to content

Commit 4324ec1

Browse files
committed
feat: TODO 해결 - 채팅 요청 세션 검증 구현
문제점: - ChatRequestValidator에 TODO 주석으로 방치된 세션 검증 - 무효한 세션으로 채팅 요청 가능한 보안 취약점 - 세션 활동 시간 추적 부재 수정사항: - ValidateUserSessionAsync 메서드 구현 - Redis 기반 사용자 세션 유효성 검사 - 세션 접근 시 마지막 활동 시간 자동 업데이트 - 세션 만료 시간 2시간 설정 - 세션 스토리지 오류 시 그레이스풀 처리 - ConfigureAwait(false) 추가로 성능 최적화
1 parent 2458278 commit 4324ec1

File tree

1 file changed

+35
-4
lines changed

1 file changed

+35
-4
lines changed

ProjectVG.Application/Services/Chat/Validators/ChatRequestValidator.cs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,23 @@ public ChatRequestValidator(
3434

3535
public async Task ValidateAsync(ChatRequestCommand command)
3636
{
37-
// TODO : 세션 검증
37+
// 세션 검증 - 사용자 활성 세션 확인
38+
await ValidateUserSessionAsync(command.UserId).ConfigureAwait(false);
3839

39-
var userExists = await _userService.ExistsByIdAsync(command.UserId);
40+
var userExists = await _userService.ExistsByIdAsync(command.UserId).ConfigureAwait(false);
4041
if (!userExists) {
4142
_logger.LogWarning("사용자 ID 검증 실패: {UserId}", command.UserId);
4243
throw new NotFoundException(ErrorCode.USER_NOT_FOUND, command.UserId);
4344
}
4445

45-
var characterExists = await _characterService.CharacterExistsAsync(command.CharacterId);
46+
var characterExists = await _characterService.CharacterExistsAsync(command.CharacterId).ConfigureAwait(false);
4647
if (!characterExists) {
4748
_logger.LogWarning("캐릭터 ID 검증 실패: {CharacterId}", command.CharacterId);
4849
throw new NotFoundException(ErrorCode.CHARACTER_NOT_FOUND, command.CharacterId);
4950
}
5051

5152
// 토큰 잔액 검증 - 예상 비용으로 미리 확인
52-
var balance = await _tokenManagementService.GetCreditBalanceAsync(command.UserId);
53+
var balance = await _tokenManagementService.GetCreditBalanceAsync(command.UserId).ConfigureAwait(false);
5354
var currentBalance = balance.CurrentBalance;
5455

5556
if (currentBalance <= 0) {
@@ -66,5 +67,35 @@ public async Task ValidateAsync(ChatRequestCommand command)
6667

6768
_logger.LogDebug("채팅 요청 검증 완료: {UserId}, {CharacterId}", command.UserId, command.CharacterId);
6869
}
70+
71+
/// <summary>
72+
/// 사용자 세션 유효성 검증
73+
/// </summary>
74+
private async Task ValidateUserSessionAsync(Guid userId)
75+
{
76+
try {
77+
var sessionKey = $"user_session:{userId}";
78+
var sessionData = await _sessionStorage.GetAsync<string>(sessionKey).ConfigureAwait(false);
79+
80+
if (sessionData == null) {
81+
_logger.LogWarning("유효하지 않은 사용자 세션: {UserId}", userId);
82+
throw new ValidationException(ErrorCode.INVALID_SESSION, "유효하지 않은 세션입니다. 다시 로그인해 주세요.");
83+
}
84+
85+
// 세션이 존재한다면 마지막 활동 시간을 업데이트
86+
var lastActivity = DateTime.UtcNow.ToString("O"); // ISO 8601 format
87+
await _sessionStorage.SetAsync(sessionKey, lastActivity, TimeSpan.FromHours(2)).ConfigureAwait(false);
88+
89+
_logger.LogDebug("세션 검증 성공 및 활동 시간 업데이트: {UserId}", userId);
90+
}
91+
catch (ValidationException) {
92+
throw; // 검증 예외는 그대로 전파
93+
}
94+
catch (Exception ex) {
95+
_logger.LogError(ex, "세션 검증 중 예상치 못한 오류: {UserId}", userId);
96+
// 세션 스토리지 오류 시에는 검증을 통과시키되 로그는 남김 (서비스 가용성 우선)
97+
_logger.LogWarning("세션 스토리지 오류로 인해 세션 검증을 건너뜁니다: {UserId}", userId);
98+
}
99+
}
69100
}
70101
}

0 commit comments

Comments
 (0)