fix: DelegatingHandler와 TokenStore의 생명주기 불일치(Scope Capture) 문제 해결을 위한 IServiceProvider 동적 해석(Resolve) 적용
TaxBaik CI/CD / build-and-deploy (push) Successful in 54s

This commit is contained in:
2026-06-29 15:39:07 +09:00
parent 917600a793
commit 3e1097f585
+14 -11
View File
@@ -10,12 +10,12 @@ using System.Text.Json;
/// </summary> /// </summary>
public class TokenRefreshHandler : DelegatingHandler public class TokenRefreshHandler : DelegatingHandler
{ {
private readonly ITokenStore _tokenStore; private readonly IServiceProvider _serviceProvider;
private readonly ILogger<TokenRefreshHandler> _logger; private readonly ILogger<TokenRefreshHandler> _logger;
public TokenRefreshHandler(ITokenStore tokenStore, ILogger<TokenRefreshHandler> logger) public TokenRefreshHandler(IServiceProvider serviceProvider, ILogger<TokenRefreshHandler> logger)
{ {
_tokenStore = tokenStore; _serviceProvider = serviceProvider;
_logger = logger; _logger = logger;
} }
@@ -23,10 +23,13 @@ public class TokenRefreshHandler : DelegatingHandler
HttpRequestMessage request, HttpRequestMessage request,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
// 최신 Scoped ITokenStore 실시간 해석 (Scope Capture 차단 및 기존 Blazor 회로 수명 공유)
var tokenStore = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<ITokenStore>(_serviceProvider);
// 요청에 access token 추가 // 요청에 access token 추가
if (!string.IsNullOrEmpty(_tokenStore.AccessToken)) if (!string.IsNullOrEmpty(tokenStore.AccessToken))
{ {
request.Headers.Authorization = new("Bearer", _tokenStore.AccessToken); request.Headers.Authorization = new("Bearer", tokenStore.AccessToken);
} }
var response = await base.SendAsync(request, cancellationToken); var response = await base.SendAsync(request, cancellationToken);
@@ -34,15 +37,15 @@ public class TokenRefreshHandler : DelegatingHandler
// 401 응답이면 토큰 갱신 시도 // 401 응답이면 토큰 갱신 시도
if (response.StatusCode == HttpStatusCode.Unauthorized) if (response.StatusCode == HttpStatusCode.Unauthorized)
{ {
if (!string.IsNullOrEmpty(_tokenStore.RefreshToken)) if (!string.IsNullOrEmpty(tokenStore.RefreshToken))
{ {
var newTokenPair = await RefreshTokenAsync(_tokenStore.RefreshToken, request, cancellationToken); var newTokenPair = await RefreshTokenAsync(tokenStore.RefreshToken, request, cancellationToken);
if (newTokenPair != null) if (newTokenPair != null)
{ {
// TokenStore에 토큰 저장 // TokenStore에 토큰 저장
_tokenStore.AccessToken = newTokenPair.AccessToken; tokenStore.AccessToken = newTokenPair.AccessToken;
_tokenStore.RefreshToken = newTokenPair.RefreshToken; tokenStore.RefreshToken = newTokenPair.RefreshToken;
_tokenStore.TokenExpiryTicks = DateTime.UtcNow.AddSeconds(newTokenPair.ExpiresIn).Ticks; tokenStore.TokenExpiryTicks = DateTime.UtcNow.AddSeconds(newTokenPair.ExpiresIn).Ticks;
// 새 토큰으로 재요청 // 새 토큰으로 재요청
request.Headers.Authorization = new("Bearer", newTokenPair.AccessToken); request.Headers.Authorization = new("Bearer", newTokenPair.AccessToken);
@@ -51,7 +54,7 @@ public class TokenRefreshHandler : DelegatingHandler
else else
{ {
_logger.LogWarning("토큰 갱신 실패 - 로그아웃"); _logger.LogWarning("토큰 갱신 실패 - 로그아웃");
_tokenStore.Clear(); tokenStore.Clear();
} }
} }
} }