홈으로 돌아가기

Dio에서 JWT 업데이트: Interceptor 접근법

이 기사는 Dio의 JWT 토큰 새로고침 메커니즘을 다룹니다: Completer를 사용한 반응형 Interceptor, exp에 의한 사전 QueryInterceptor. Basic/Bearer 방식 비교, 이중 토큰 아키텍처, 프로덕션 코드 예제.

Dio 토큰 자동 새로고침: 이론에서 코드까지
Advertisement 728x90

Dio에서 JWT 토큰 자동 갱신: 인터셉터와 쿼리 인터셉터 활용

서버는 보호된 엔드포인트에 대해 Authorization 헤더를 통해 인증을 검증합니다. 이 헤더는 <인증-스킴> <인증-매개변수> 형식으로 구성되며, 미들웨어가 처리합니다. 데이터가 누락되거나 유효하지 않으면 401 Unauthorized 또는 403 Forbidden을 반환합니다.

주요 스킴:

  • Basic: Base64로 인코딩된 로그인:비밀번호 (Authorization: Basic bG9naW46cGFzc3dvcmQ=). 쉽게 디코딩 가능해 보안 수준이 낮습니다.
  • Bearer: JWT 토큰 (Authorization: Bearer <토큰>). 만료 기능을 지원하며, 갱신이 필요합니다.

JWT는 헤더(알고리즘), 페이로드(사용자 데이터, exp), 서명(서버 비밀)으로 구성됩니다. 형식: Base64로 인코딩된 {헤더}.{페이로드}.{서명}.

Google AdInline article slot

JWT 구조와 갱신

페이로드에는 exp(만료 시간)가 포함됩니다. 401 오류 발생 시, 클라이언트는 미들웨어 없이 보호된 엔드포인트를 통해 갱신을 요청합니다.

이중 토큰 시스템:

  • 액세스 토큰: 짧은 수명(분 단위), API 요청에 사용.
  • 리프레시 토큰: 긴 수명, 새로운 액세스 토큰 생성에 사용.

만료된 토큰 처리 전략

로그아웃 (가장 간단한 접근법)

401 오류 시 — 로그아웃. 구현은 간단하지만 사용자에게 불편합니다.

Google AdInline article slot

장점:

  • 최소한의 코드.

단점:

  • 빈번한 재로그인.
  • 이중 토큰과 호환되지 않음.

오류 시 갱신 (인터셉터)

Dio의 Interceptor를 통해 구현됩니다. onRequest에서 토큰을 추가하고, onError에서 401을 처리합니다.

Google AdInline article slot
class TokenInterceptor extends Interceptor {
  final TokenStorage _storage;

  TokenInterceptor(this._storage);

  @override
  Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    final token = await _storage.getToken();
    if (token != null) {
      options.headers['Authorization'] = 'Bearer $token';
    }
    handler.next(options);
  }
}

설정:

final dio = Dio()..interceptors.add(TokenInterceptor(TokenStorage()));

onError에서 401 처리:

  • _isRefreshing 플래그 확인.
  • 갱신 중이 아니면 — 별도의 Dio를 통해 갱신 시작.
  • 대기 중인 요청은 Completer<void> _refreshCompleter를 통해 대기.
Future<String?> _updateToken() async {
  final oldToken = await _storage.getToken();
  try {
    final dio = Dio();
    final response = await dio.get('/auth/refresh/', headers: {'Authorization': 'Bearer $oldToken'});
    final newToken = (response.data as Map<String, dynamic>)['token'];
    await _storage.setNewToken(newToken);
    return newToken;
  } catch (e) {
    await _storage.clearToken();
    return null;
  }
}

전체 onError 로직은 병렬 요청을 동기화하고, 새 토큰으로 재시도합니다.

장점:

  • 이중 토큰과 작동.
  • 외부 라이브러리 불필요.

단점:

  • 대량 재시도 시 서버에 부하 발생.
  • 응답 지연(오류 + 갱신 + 재시도).

사전 갱신 (쿼리 인터셉터)

JWT의 exp를 사용해 만료 전에 갱신합니다. QueryInterceptor는 순차적 요청 처리를 보장합니다.

JWT를 파싱하여 exp 추출:

  • Base64 페이로드 디코딩.
  • JSON 파싱, 타임스탬프 획득.

장점: 401 오류 차단 없음. 단점: 엄격한 큐, 병렬 요청이 차단됨.

핵심 요약

  • Interceptor를 사용해 Completer로 동기화된 반응적 갱신 구현.
  • QueryInterceptorexp 기반 사전 갱신에 적합.
  • 토큰을 격리된 저장소에 보관, 갱신용 별도 Dio 사용.
  • 다중 401 발생 시 경쟁 조건 처리.
  • 이중 토큰으로 보안 강화: 짧은 액세스 + 리프레시.

— Editorial Team

Advertisement 728x90

다음 읽기