[Flutter] 토큰 만료로 인한 에러 로그아웃으로 처리하기

겨레·2024년 7월 15일
0
post-thumbnail

현재 엑세스 토큰의 유효 기간은 5분, 리프레시 토큰은 하루로 설정되어 있음
그래서 토큰 만료로 인해 중간중간 오류가 발생하는 문제가 생김ㅠㅠ

현재 이런 에러를 처리할 수 있는 로직은???
방법은 다양한데, 그중에서도 가장 평범한 방법인 로그아웃 시켜보자!


splash_screen.dart 코드를 보면...

리프레시 토큰, 엑세스 토큰을 null 체크만 하고 있음.
그럼 토큰들이 유효 기간이 만료됐든, 안 됐든 지금 무조건 있기만 하면 다음 페이지로 넘겨버림.


그런데 페이지에서 리프레시 토큰, 엑세스 토큰이 필요한 API를 사용 중이라면,
이 토큰들은 유효하지 않아서 API를 쓰지 못하게 된다.

그럼 토큰을 재발급 받으면 되겠지? 어떻게? 다시 로그인해서!

새로 리프레시 토큰으로 액세스 토큰을 한 번 새로 발급받으려고 시도 했을 때...

  • 발급이 된 경우 👉 홈 스크린으로 전환
  • 발급이 안 된 경우 👉 만료 됐거나 어떤 문제가 발생했다는 뜻이므로 다시 로그인 페이지로 전환시키는 로직을 추가하면 된다.

  • login_screen.dart 코드


  • splash_screen.dart 코드 추가
    login_screen.dart 회원가입 버튼에 있던 코드 긁어와서 추가 및 수정해 준 거!


    근데... 에러 발생!!! dio랑 IP가 필요함...

    login_screen.dart으로 가서...
// 요것만!!!
    const emulatorIp = '10.0.2.2:3000';
    const simulatorIp = '127.0.0.1:3000';

    final ip = Platform.isIOS ? simulatorIp : emulatorIp;

이 코드 잘라내서 const/data로 빼줌!

그리고 다시 splash_screen.dart로 돌아가서 Dio는 그냥 새로 생성해준다!
추후 전부 통합해서 관리하는 방법 배울 예정...



여기서 추가적으로 에러 발생 시, splash_screen.dart 코드에서 에러를 던져주자!

// ignore_for_file: unused_element

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_actual/common/const/colors.dart';
import 'package:flutter_actual/common/const/data.dart';
import 'package:flutter_actual/common/layout/default_layout.dart';
import 'package:flutter_actual/common/view/root_tab.dart';
import 'package:flutter_actual/user/login_screen.dart';

class SplashScreen extends StatefulWidget {
  const SplashScreen({super.key});

  
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  
  void initState() {
    super.initState();

    // deleteToken();
    checkToken();
  }

  void deleteToken() async {
    await storage.deleteAll();
  }

  // initState()에서는 await 불가능!
  // await storage.read(key: REFRESH_TOKEN_KEY);
  // await storage.read(key: ACCESS_TOKEN_KEY);

  // 함수를 만들어서 쓰자! -> 이제 스토리지로부터 토큰 가져올 수 있음
  void checkToken() async {
    final refeshToken = await storage.read(key: REFRESH_TOKEN_KEY);
    final accessToken = await storage.read(key: ACCESS_TOKEN_KEY);

    final dio = Dio();

    try {
      final resp = await dio.post(
        'http://$ip/auth/token',
        options: Options(
          headers: {
            'authorizaiton': 'Bearer $refeshToken',
          },
        ),
      );
      // 에러 발생 X (정상일 때) => RootTab 으로
      Navigator.of(context).pushAndRemoveUntil(
        MaterialPageRoute(
          builder: (_) => const RootTab(),
        ),
        (route) => false,
      );
    } catch (e) {
      // 에러 발생 시 => LoginScreen으로
      Navigator.of(context).pushAndRemoveUntil(
          MaterialPageRoute(
            builder: (_) => const LoginScreen(),
          ),
          (route) => false);
    }
  }

  
  Widget build(BuildContext context) {
    return DefaultLayout(
      backgroundColor: PRIMARY_COLOR,
      child: SizedBox(
        width: MediaQuery.of(context).size.width,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Image.asset(
              'asset/img/logo/logo.png',
              width: MediaQuery.of(context).size.width / 2,
            ),
            const Text(
              'Food Order App',
              style: TextStyle(
                  fontFamily: 'NotoSans',
                  color: Colors.white,
                  fontSize: 30,
                  fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 16),
            const CircularProgressIndicator(
              color: Colors.white,
            )
          ],
        ),
      ),
    );
  }
}

이전에 작성했던 splash_screen.dart 코드와 조금 달라진 부분을 찾을 수 있을 것!!!


이렇게 하고 재시작 하면...

토큰이 분명 이 안에 들어있음에도 이렇게 로그인 화면이 나온다.
로그인도 잘 된다.

💣 트러블이슈
강의에서는 로그인 하고 재실행 시, 바로 홈화면(RootTab)이 보이는데 왜 나는 다시 로그인 화면이 나올까?

👉 오타 문제였음...
'authorization': 'Bearer $refreshToken'
수정 후 해결!

profile
호떡 신문지에서 개발자로 환생

0개의 댓글