@@ -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