Skip to content

Commit 794e829

Browse files
committed
feat: access 토큰 메모리 저장 + access 토큰 재발급
1 parent 11d2031 commit 794e829

File tree

1 file changed

+71
-58
lines changed

1 file changed

+71
-58
lines changed

Assets/Infrastructure/Auth/TokenManager.cs

Lines changed: 71 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections;
23
using System.Security.Cryptography;
34
using System.Text;
45
using UnityEngine;
@@ -14,9 +15,8 @@ namespace ProjectVG.Infrastructure.Auth
1415
/// </summary>
1516
public class TokenManager : MonoBehaviour
1617
{
17-
private const string ACCESS_TOKEN_KEY = "access_token";
18+
// AccessToken은 메모리에만 저장하므로 ACCESS_TOKEN_KEY, TOKEN_EXPIRY_KEY 는 제거
1819
private const string REFRESH_TOKEN_KEY = "refresh_token";
19-
private const string TOKEN_EXPIRY_KEY = "token_expiry";
2020
private const string USER_ID_KEY = "user_id";
2121
private const string ENCRYPTION_KEY = "ProjectVG_OAuth2_Secure_Key_2024";
2222

@@ -54,6 +54,13 @@ private void Awake()
5454
_instance = this;
5555
DontDestroyOnLoad(gameObject);
5656
LoadTokensFromStorage();
57+
58+
// 앱 시작 시 RefreshToken이 있으면 자동으로 AccessToken 복구 시도
59+
if (HasRefreshToken && !IsRefreshTokenExpired())
60+
{
61+
Debug.Log("[TokenManager] RefreshToken 발견 - 자동 AccessToken 복구 시작");
62+
StartCoroutine(AutoRecoverAccessTokenCoroutine());
63+
}
5764
}
5865
else if (_instance != this)
5966
{
@@ -74,21 +81,11 @@ public void SaveTokens(TokenSet tokenSet)
7481

7582
try
7683
{
84+
// AccessToken은 메모리에만 저장 (영속적 저장 안함)
7785
_currentAccessToken = tokenSet.AccessToken;
7886
_currentRefreshToken = tokenSet.RefreshToken;
7987
_currentUserId = tokenSet.RefreshToken?.DeviceId;
8088

81-
// Access Token 저장 (암호화)
82-
var accessTokenData = new TokenStorageData
83-
{
84-
Token = _currentAccessToken.Token,
85-
ExpiresAt = _currentAccessToken.ExpiresAt,
86-
TokenType = _currentAccessToken.TokenType,
87-
Scope = _currentAccessToken.Scope
88-
};
89-
var encryptedAccessToken = EncryptData(JsonConvert.SerializeObject(accessTokenData));
90-
PlayerPrefs.SetString(ACCESS_TOKEN_KEY, encryptedAccessToken);
91-
9289
// Refresh Token 저장 (강력한 암호화)
9390
string encryptedRefreshToken = null;
9491
if (_currentRefreshToken != null)
@@ -109,8 +106,7 @@ public void SaveTokens(TokenSet tokenSet)
109106
PlayerPrefs.DeleteKey(REFRESH_TOKEN_KEY);
110107
}
111108

112-
// 만료 시간 저장
113-
PlayerPrefs.SetString(TOKEN_EXPIRY_KEY, _currentAccessToken.ExpiresAt.ToString("O"));
109+
// AccessToken 만료 시간은 메모리에만 보관 (PlayerPrefs 저장 안함)
114110

115111
// User ID 저장
116112
if (!string.IsNullOrEmpty(_currentUserId))
@@ -121,9 +117,8 @@ public void SaveTokens(TokenSet tokenSet)
121117
PlayerPrefs.Save();
122118

123119
Debug.Log("=== 🔐 TokenManager 토큰 저장 완료 ===");
124-
Debug.Log($"[TokenManager] Access Token 저장 위치: PlayerPrefs['{ACCESS_TOKEN_KEY}']");
120+
Debug.Log($"[TokenManager] Access Token 저장: 메모리 전용 (영속적 저장 안함)");
125121
Debug.Log($"[TokenManager] Access Token 만료: {_currentAccessToken.ExpiresAt}");
126-
Debug.Log($"[TokenManager] Access Token 암호화: {!string.IsNullOrEmpty(encryptedAccessToken)}");
127122

128123
if (_currentRefreshToken != null)
129124
{
@@ -137,7 +132,6 @@ public void SaveTokens(TokenSet tokenSet)
137132
}
138133

139134
Debug.Log($"[TokenManager] User ID 저장 위치: PlayerPrefs['{USER_ID_KEY}'] = {_currentUserId}");
140-
Debug.Log($"[TokenManager] 만료 시간 저장 위치: PlayerPrefs['{TOKEN_EXPIRY_KEY}'] = {_currentAccessToken.ExpiresAt:O}");
141135
Debug.Log("=== 토큰 저장 완료 ===");
142136

143137
OnTokensUpdated?.Invoke(tokenSet);
@@ -226,22 +220,10 @@ public void UpdateAccessToken(string newAccessToken, int expiresInSeconds)
226220

227221
try
228222
{
223+
// AccessToken은 메모리에만 업데이트 (영속적 저장 안함)
229224
_currentAccessToken = new AccessToken(newAccessToken, expiresInSeconds, "Bearer", "oauth2");
230225

231-
// Access Token만 업데이트
232-
var accessTokenData = new TokenStorageData
233-
{
234-
Token = _currentAccessToken.Token,
235-
ExpiresAt = _currentAccessToken.ExpiresAt,
236-
TokenType = _currentAccessToken.TokenType,
237-
Scope = _currentAccessToken.Scope
238-
};
239-
var encryptedAccessToken = EncryptData(JsonConvert.SerializeObject(accessTokenData));
240-
PlayerPrefs.SetString(ACCESS_TOKEN_KEY, encryptedAccessToken);
241-
PlayerPrefs.SetString(TOKEN_EXPIRY_KEY, _currentAccessToken.ExpiresAt.ToString("O"));
242-
PlayerPrefs.Save();
243-
244-
Debug.Log("[TokenManager] Access Token 갱신 완료");
226+
Debug.Log("[TokenManager] Access Token 갱신 완료 (메모리 전용)");
245227
Debug.Log($"[TokenManager] 새로운 만료 시간: {_currentAccessToken.ExpiresAt}");
246228

247229
var tokenSet = new TokenSet(_currentAccessToken, _currentRefreshToken);
@@ -261,13 +243,13 @@ public void ClearTokens()
261243
{
262244
try
263245
{
246+
// 메모리에서 AccessToken 제거
264247
_currentAccessToken = null;
265248
_currentRefreshToken = null;
266249
_currentUserId = null;
267250

268-
PlayerPrefs.DeleteKey(ACCESS_TOKEN_KEY);
251+
// RefreshToken만 PlayerPrefs에서 삭제 (기존 ACCESS_TOKEN_KEY, TOKEN_EXPIRY_KEY 삭제 로직 제거)
269252
PlayerPrefs.DeleteKey(REFRESH_TOKEN_KEY);
270-
PlayerPrefs.DeleteKey(TOKEN_EXPIRY_KEY);
271253
PlayerPrefs.DeleteKey(USER_ID_KEY);
272254
PlayerPrefs.Save();
273255

@@ -288,20 +270,9 @@ private void LoadTokensFromStorage()
288270
{
289271
try
290272
{
291-
// Access Token 로드
292-
if (PlayerPrefs.HasKey(ACCESS_TOKEN_KEY))
293-
{
294-
var encryptedAccessToken = PlayerPrefs.GetString(ACCESS_TOKEN_KEY);
295-
var decryptedAccessToken = DecryptData(encryptedAccessToken);
296-
var accessTokenData = JsonConvert.DeserializeObject<TokenStorageData>(decryptedAccessToken);
297-
298-
_currentAccessToken = new AccessToken(
299-
accessTokenData.Token,
300-
accessTokenData.ExpiresAt,
301-
accessTokenData.TokenType,
302-
accessTokenData.Scope
303-
);
304-
}
273+
// AccessToken은 저장소에서 로드하지 않음 (메모리 전용)
274+
// 앱 시작 시 AccessToken은 null 상태로 시작
275+
_currentAccessToken = null;
305276

306277
// Refresh Token 로드
307278
if (PlayerPrefs.HasKey(REFRESH_TOKEN_KEY))
@@ -324,13 +295,8 @@ private void LoadTokensFromStorage()
324295
}
325296

326297
Debug.Log("=== 🔍 TokenManager 저장소에서 토큰 로드 완료 ===");
327-
Debug.Log($"[TokenManager] Access Token 로드 위치: PlayerPrefs['{ACCESS_TOKEN_KEY}']");
328-
Debug.Log($"[TokenManager] Access Token 존재: {_currentAccessToken != null}");
329-
if (_currentAccessToken != null)
330-
{
331-
Debug.Log($"[TokenManager] Access Token 만료: {_currentAccessToken.ExpiresAt}");
332-
Debug.Log($"[TokenManager] Access Token 유효: {!_currentAccessToken.IsExpired()}");
333-
}
298+
Debug.Log($"[TokenManager] Access Token: 메모리 전용 (영속적 로드 안함)");
299+
Debug.Log($"[TokenManager] Access Token 상태: null (앱 시작 시 기본값)");
334300

335301
Debug.Log($"[TokenManager] Refresh Token 로드 위치: PlayerPrefs['{REFRESH_TOKEN_KEY}']");
336302
Debug.Log($"[TokenManager] Refresh Token 존재: {_currentRefreshToken != null}");
@@ -341,7 +307,6 @@ private void LoadTokensFromStorage()
341307
}
342308

343309
Debug.Log($"[TokenManager] User ID 로드 위치: PlayerPrefs['{USER_ID_KEY}'] = {_currentUserId}");
344-
Debug.Log($"[TokenManager] 만료 시간 로드 위치: PlayerPrefs['{TOKEN_EXPIRY_KEY}']");
345310
Debug.Log("=== 토큰 로드 완료 ===");
346311
}
347312
catch (Exception ex)
@@ -418,10 +383,9 @@ public string GetDebugInfo()
418383
{
419384
var info = "TokenManager Debug Info:\n";
420385
info += $"=== 저장 위치 정보 ===\n";
421-
info += $"Access Token 저장: PlayerPrefs['{ACCESS_TOKEN_KEY}']\n";
386+
info += $"Access Token 저장: 메모리 전용 (영속적 저장 안함)\n";
422387
info += $"Refresh Token 저장: PlayerPrefs['{REFRESH_TOKEN_KEY}']\n";
423388
info += $"User ID 저장: PlayerPrefs['{USER_ID_KEY}']\n";
424-
info += $"만료 시간 저장: PlayerPrefs['{TOKEN_EXPIRY_KEY}']\n";
425389
info += $"=== 토큰 상태 ===\n";
426390
info += $"Has Valid Tokens: {HasValidTokens}\n";
427391
info += $"Has Refresh Token: {HasRefreshToken}\n";
@@ -445,6 +409,55 @@ public string GetDebugInfo()
445409

446410
return info;
447411
}
412+
413+
/// <summary>
414+
/// 앱 시작 시 RefreshToken으로 AccessToken 자동 복구
415+
/// </summary>
416+
private IEnumerator AutoRecoverAccessTokenCoroutine()
417+
{
418+
// TokenRefreshService가 초기화될 때까지 대기
419+
yield return new WaitForSeconds(0.5f);
420+
421+
if (TokenRefreshService.Instance != null)
422+
{
423+
Debug.Log("[TokenManager] TokenRefreshService를 통해 AccessToken 복구 시도");
424+
425+
// 비동기 호출을 코루틴에서 처리
426+
StartCoroutine(TryRefreshTokenCoroutine());
427+
}
428+
else
429+
{
430+
Debug.LogWarning("[TokenManager] TokenRefreshService가 아직 초기화되지 않았습니다.");
431+
}
432+
}
433+
434+
/// <summary>
435+
/// RefreshToken으로 AccessToken 복구 코루틴
436+
/// </summary>
437+
private IEnumerator TryRefreshTokenCoroutine()
438+
{
439+
var refreshTask = TokenRefreshService.Instance.RefreshAccessTokenAsync();
440+
441+
// UniTask를 코루틴에서 기다림
442+
yield return new WaitUntil(() => refreshTask.Status != Cysharp.Threading.Tasks.UniTaskStatus.Pending);
443+
444+
if (refreshTask.Status == Cysharp.Threading.Tasks.UniTaskStatus.Succeeded)
445+
{
446+
bool success = refreshTask.GetAwaiter().GetResult();
447+
if (success)
448+
{
449+
Debug.Log("[TokenManager] 앱 시작 시 AccessToken 자동 복구 성공");
450+
}
451+
else
452+
{
453+
Debug.LogWarning("[TokenManager] 앱 시작 시 AccessToken 자동 복구 실패");
454+
}
455+
}
456+
else
457+
{
458+
Debug.LogError("[TokenManager] AccessToken 복구 중 오류 발생");
459+
}
460+
}
448461
}
449462

450463
/// <summary>

0 commit comments

Comments
 (0)