Flutter에서 JWT 토큰을 관리하는 방법은 주로 로그인 및 인증이 필요한 앱에서 중요한 역할을 합니다. 기본적으로 JWT 토큰을 생성하고 저장한 후, 서버에 요청을 보낼 때마다 이를 사용하여 인증을 처리합니다. 아래는 Flutter 앱에서 JWT 토큰을 관리하는 데 필요한 기본적인 단계와 예제 코드입니다.
Flutter에서 JWT 토큰을 관리하는 방법은 주로 로그인 및 인증이 필요한 앱에서 중요한 역할을 합니다. 기본적으로 JWT 토큰을 생성하고 저장한 후, 서버에 요청을 보낼 때마다 이를 사용하여 인증을 처리합니다. 아래는 Flutter 앱에서 JWT 토큰을 관리하는 데 필요한 기본적인 단계와 예제 코드입니다.
1. JWT 토큰 관리의 개요
JWT 토큰은 클라이언트와 서버 간의 인증을 위해 사용되는 토큰입니다. 사용자가 로그인하면 서버는 JWT 토큰을 발급하고, 클라이언트는 이를 저장하여 다음 요청에 사용합니다. JWT 토큰은 주로 access_token과 refresh_token 두 가지로 구성됩니다.
- access_token: 짧은 유효 기간을 가지며, 이를 통해 사용자를 인증합니다.
- refresh_token: 유효 기간이 길며, access_token이 만료되면 새 토큰을 발급받는 데 사용됩니다.
2. Flutter에 필요한 패키지 설치
Flutter에서 HTTP 요청과 로컬 저장소를 관리하려면 다음 두 가지 패키지를 사용합니다.
- dio: HTTP 요청을 간편하게 처리할 수 있는 패키지입니다.
- shared_preferences: JWT 토큰을 로컬에 저장하고 불러올 때 사용합니다.
pubspec.yaml에 패키지 추가
dependencies:
flutter:
sdk: flutter
dio: ^5.0.0
shared_preferences: ^2.0.15
3. 토큰 저장 및 로드
토큰을 저장하거나 불러올 때는 shared_preferences를 사용합니다.
예제 코드: JWT 토큰 저장 및 로드
import 'package:shared_preferences/shared_preferences.dart';
class TokenManager {
Future<void> saveToken(String token) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('jwt_token', token);
}
Future<String?> loadToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('jwt_token');
}
Future<void> clearToken() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('jwt_token');
}
}
- saveToken: 토큰을 저장하는 메서드입니다.
- loadToken: 저장된 토큰을 불러오는 메서드입니다.
- clearToken: 로그아웃 시 토큰을 삭제합니다
4. 인증 요청 보내기 (Dio와 JWT 사용)
Dio를 사용하여 서버에 인증 요청을 보낼 때, Authorization 헤더에 Bearer <token> 형식으로 JWT 토큰을 포함합니다.
예제 코드: 요청 인터셉터 설정
import 'package:dio/dio.dart';
class ApiClient {
final Dio _dio = Dio();
final TokenManager _tokenManager = TokenManager();
ApiClient() {
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) async {
final token = await _tokenManager.loadToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
return handler.next(options);
},
onError: (DioError e, handler) {
if (e.response?.statusCode == 401) {
// Handle token expiration and refresh token if needed
print('Unauthorized! Token may have expired.');
}
return handler.next(e);
},
));
}
Future fetchData() async {
try {
return await _dio.get('<https://api.example.com/protected-endpoint>');
} on DioError catch (e) {
return e.response!;
}
}
}
- onRequest: HTTP 요청을 보내기 전에 인터셉터에서 Authorization 헤더에 JWT 토큰을 추가합니다.
- onError: 서버에서 401 Unauthorized 응답을 받으면 토큰이 만료된 것으로 간주하고 추가적인 처리를 진행할 수 있습니다.
5. JWT 토큰 갱신 (Refresh Token 활용)
access_token이 만료되면 refresh_token을 사용하여 새 토큰을 발급받을 수 있습니다. 토큰 갱신 요청은 일반적으로 백그라운드에서 자동으로 처리되며, 성공적으로 갱신된 토큰은 다시 저장됩니다.
예제 코드: 토큰 갱신 로직
class ApiClient {
final Dio _dio = Dio();
final TokenManager _tokenManager = TokenManager();
ApiClient() {
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) async {
final token = await _tokenManager.loadToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
return handler.next(options);
},
onError: (DioError e, handler) async {
if (e.response?.statusCode == 401) {
// Access token이 만료된 경우
final refreshToken = await _tokenManager.loadToken();
final newToken = await _refreshToken(refreshToken);
if (newToken != null) {
await _tokenManager.saveToken(newToken);
e.requestOptions.headers['Authorization'] = 'Bearer $newToken';
final retryRequest = await _dio.request(
e.requestOptions.path,
options: Options(
method: e.requestOptions.method,
headers: e.requestOptions.headers,
),
);
return handler.resolve(retryRequest);
}
}
return handler.next(e);
},
));
}
Future<string?> _refreshToken(String? refreshToken) async {
try {
final response = await _dio.post(
'<https://api.example.com/refresh>',
data: {'refresh_token': refreshToken},
);
return response.data['access_token'];
} catch (e) {
print('Token refresh failed');
return null;
}
}
}
</string?>
- onError: 401 Unauthorized 응답이 있을 때 _refreshToken() 메서드를 호출하여 새 access_token을 받아옵니다.
- _refreshToken(): 서버에 refresh_token을 보내고 새 access_token을 발급받습니다.
6. 사용 흐름 요약
- 로그인 시 서버에서 access_token과 refresh_token을 발급받고, 이를 shared_preferences에 저장합니다.
- 요청 시 Dio 인터셉터에서 access_token을 헤더에 추가합니다.
- 토큰 만료 시 401 Unauthorized 응답을 받으면 refresh_token을 사용하여 새 access_token을 발급받고 요청을 재시도합니다.
- 로그아웃 시 clearToken 메서드를 호출하여 저장된 토큰을 삭제합니다.
'Flutter' 카테고리의 다른 글
플러터 기본기 다지기 - 1 (1) | 2024.11.18 |
---|---|
Retrofit 구현과 활용 (0) | 2024.11.15 |
Flutter 상태 관리 (0) | 2024.11.15 |
Flutter Animation 처리 (0) | 2024.11.15 |
Flutter 기본설정 (0) | 2024.11.14 |