@@ -14,6 +14,8 @@ class DioProvider {
1414
1515 final StorageService _storageService = StorageService ();
1616
17+ bool _isRefreshingToken = false ;
18+
1719 static BuildContext ? _navigatorContext;
1820 static BuildContext ? get navigatorContext => _navigatorContext;
1921
@@ -39,8 +41,24 @@ class DioProvider {
3941 }
4042 return handler.next (options);
4143 },
44+ // 기존 구현에서는 401 상태가 오면 바로 로그아웃을 호출하여
45+ // 토큰이 만료된 경우에도 자동 로그인 상태가 해제되는 문제가 있었다.
4246 onError: (DioException e, handler) async {
4347 if (e.response? .statusCode == 401 ) {
48+ if (! _isRefreshingToken) {
49+ _isRefreshingToken = true ;
50+ final refreshed = await _refreshToken ();
51+ _isRefreshingToken = false ;
52+ if (refreshed) {
53+ try {
54+ final response = await _dio.fetch (e.requestOptions);
55+ return handler.resolve (response);
56+ } catch (err) {
57+ // If retry fails, fall through to logout
58+ }
59+ }
60+ }
61+
4462 if (_navigatorContext != null ) {
4563 try {
4664 Provider .of <AuthModel >(_navigatorContext! , listen: false )
@@ -60,4 +78,33 @@ class DioProvider {
6078 },
6179 ));
6280 }
81+
82+ Future <bool > _refreshToken () async {
83+ final refreshToken = await _storageService.getRefreshToken ();
84+ if (refreshToken == null ) {
85+ return false ;
86+ }
87+
88+ final refreshDio = Dio (BaseOptions (baseUrl: _dio.options.baseUrl));
89+ try {
90+ final response = await refreshDio.post (
91+ SESSION_REFRESH_URL ,
92+ data: {'token' : refreshToken},
93+ );
94+
95+ if (response.statusCode == 200 && response.data != null ) {
96+ final newAccessToken = response.data['accessToken' ];
97+ final newRefreshToken = response.data['refreshToken' ];
98+
99+ if (newAccessToken != null && newRefreshToken != null ) {
100+ await _storageService.saveTokens (
101+ accessToken: newAccessToken, refreshToken: newRefreshToken);
102+ return true ;
103+ }
104+ }
105+ } catch (e) {
106+ print ('Error refreshing token in DioProvider: $e ' );
107+ }
108+ return false ;
109+ }
63110}
0 commit comments