You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter中使用SharedPreferences存储Token/Cookie处理登录态及API请求的相关问题

Flutter中使用SharedPreferences存储Token/Cookie处理登录态及API请求的相关问题

Hey there! Let's break this down step by step since you're new to Flutter—no worries, it's simpler than it sounds 😊

1. 登录请求中获取Token

首先,你需要发送登录请求(带上用户名和密码),然后从API返回的响应里提取token。这里给你两种常见的实现方式,用原生http包或者更易用的dio包:

http包的示例:

import 'package:http/http.dart' as http;
import 'dart:convert';

Future<void> login(String username, String password) async {
  final response = await http.post(
    Uri.parse('https://your-api-url.com/login'),
    body: {
      'username': username,
      'password': password,
    },
  );

  if (response.statusCode == 200) {
    // 解析响应JSON,取出token(字段名根据你的API返回调整,比如`token`或`access_token`)
    final Map<String, dynamic> data = jsonDecode(response.body);
    final String token = data['token'];
    
    // 拿到token后,下一步就是存储它,咱们接着看
    await saveToken(token);
  } else {
    // 处理登录失败的情况,比如提示用户用户名密码错误
    throw Exception('登录失败,请检查账号密码');
  }
}

dio包的示例(更推荐,拦截器等功能更强大):

先在pubspec.yaml添加依赖:

dependencies:
  dio: ^5.4.0+1

然后写登录逻辑:

import 'package:dio/dio.dart';

Future<void> login(String username, String password) async {
  final dio = Dio();
  try {
    final response = await dio.post(
      'https://your-api-url.com/login',
      data: {
        'username': username,
        'password': password,
      },
    );
    
    // 提取token
    final String token = response.data['token'];
    await saveToken(token);
  } on DioException catch (e) {
    // 处理请求错误
    throw Exception('登录失败:${e.response?.data['message'] ?? '未知错误'}');
  }
}

2. 用SharedPreferences存储Token

接下来咱们把拿到的token存在SharedPreferences里,这样就算退出APP再打开,token还在。

首先添加shared_preferences依赖到pubspec.yaml

dependencies:
  shared_preferences: ^2.2.2

然后封装一个存储和读取token的方法:

import 'package:shared_preferences/shared_preferences.dart';

// 存储token
Future<void> saveToken(String token) async {
  final prefs = await SharedPreferences.getInstance();
  await prefs.setString('auth_token', token);
}

// 读取token
Future<String?> getToken() async {
  final prefs = await SharedPreferences.getInstance();
  return prefs.getString('auth_token');
}

// 清除token(比如用户退出登录时)
Future<void> clearToken() async {
  final prefs = await SharedPreferences.getInstance();
  await prefs.remove('auth_token');
}

登录成功后调用saveToken(token)就完成存储啦!

3. 后续API请求自动携带Token

现在每次发API请求时,咱们需要把token放到请求头里(一般是Authorization: Bearer {token}的格式,具体要看你的API要求)。

http包的请求示例:

Future<Map<String, dynamic>> fetchUserData() async {
  final token = await getToken();
  if (token == null) {
    // 没有token,说明用户未登录,跳转到登录页
    // 这里可以用Navigator.pushReplacement跳转
    throw Exception('用户未登录');
  }

  final response = await http.get(
    Uri.parse('https://your-api-url.com/user'),
    headers: {
      'Authorization': 'Bearer $token', // 按API要求的格式设置
      'Content-Type': 'application/json',
    },
  );

  if (response.statusCode == 200) {
    return jsonDecode(response.body);
  } else if (response.statusCode == 401) {
    // token过期或无效,清除存储的token并跳回登录页
    await clearToken();
    // Navigator.pushReplacement(...)
    throw Exception('登录已过期,请重新登录');
  } else {
    throw Exception('请求失败');
  }
}

dio的拦截器自动加token(更高效,不用每次手动写):

可以创建一个全局的Dio实例,添加拦截器自动在请求头里加token:

import 'package:dio/dio.dart';

Dio createDioInstance() {
  final dio = Dio();
  
  // 添加请求拦截器
  dio.interceptors.add(InterceptorsWrapper(
    onRequest: (options, handler) async {
      final token = await getToken();
      if (token != null) {
        options.headers['Authorization'] = 'Bearer $token';
      }
      return handler.next(options);
    },
    onResponse: (response, handler) {
      return handler.next(response);
    },
    onError: (DioException e, handler) {
      if (e.response?.statusCode == 401) {
        // token过期,清除token并跳转登录页
        clearToken();
        // Navigator.pushReplacement(...)
      }
      return handler.next(e);
    },
  ));
  
  return dio;
}

// 之后用这个实例发请求就自动带token了
final dio = createDioInstance();

Future<Map<String, dynamic>> fetchUserData() async {
  try {
    final response = await dio.get('https://your-api-url.com/user');
    return response.data;
  } on DioException catch (e) {
    throw Exception('请求失败:${e.message}');
  }
}

一些实用小建议

  • 把这些token相关的方法封装成一个AuthService类,代码更整洁,方便全局调用。
  • 记得处理token过期的情况(比如API返回401状态码),这时候要清除本地token并引导用户重新登录。
  • 如果有更高的安全需求,可以考虑用flutter_secure_storage来加密存储token,比SharedPreferences更安全。

备注:内容来源于stack exchange,提问作者Vedo

火山引擎 最新活动