我正在尝试存储从 Rest API 获取的授权令牌,然后在 Flutter 中其他 API 调用的 headers 中使用它

I am trying to store the Authorization Token fetched from the Rest API and then use it in the headers of other API calls in Flutter

正如问题的标题所解释的大部分内容,但仍会详细说明。 因此,我正在使用 POST 方法调用 API 并注册一个用户,该用户给我的响应数据仅包含在调用其他 API 时需要使用的授权令牌。

现在我想存储令牌并在 headers 中使用它,同时进行其他 API 调用。 我特此附上一些代码片段,它们可能会展示我实际做了什么以及需要做什么才能获得特定结果。 我收到了获取密钥的 API 响应,但我无法理解为什么它没有被存储以及为什么我不能在 headers.

中使用它

API 调用 returns 只是响应中的标记

   final storage = SecureStorage();
Future<UserRegistration> registration(dynamic param) async {
    var client = http.Client();
    try {
      var response = await client
          .post(Uri.https("baseURL", "endpoint"),
              body: param)
          .timeout(Duration(seconds: TIME_CONST))
          .catchError(handleError);

      if (response.statusCode == 201) {
        print('Response Body: ${response.body}');
        final data = jsonDecode(response.body);

    ///////Using the flutter secure storage here to save the token

         var token = storage.writeSecureToken('key', data['key']);
          print("Token Here $token");
        return UserRegistration(
          key: data['key'],
          status: true,
        );
      } else {
        print("Something went wrong");
        return param;
      }
    } on SocketException {
      throw FetchDataException('message', 'url');
    } on TimeoutException {
      throw ApiNotRespondingException("message", "url");
    }
  }

API 我收到的回复

Response Body: {"key":"8fb303212871a80899f0b883f3554b189fddf24b"}
我正在进行的

API 调用需要授权 Header 作为在先前响应中收到的密钥。

Future<PhoneOTPValidate> phoneOTPvalidate(dynamic param) async {
    var client = http.Client();
    var token = storage.readSecureToken('key');
    try {
      var response = await client
          .post(
              Uri.https("baseURL", "endpoint"),
              headers: <String, String>{
                'Authorization': 'Token $token',
              },
              body: param)
          .timeout(Duration(seconds: TIME_CONST))
          .catchError(handleError);

      if (response.statusCode == 200) {
        print('Response Body: ${response.body}');
        final data = jsonDecode(response.body);
        return PhoneOTPValidate(
          status: data['success'],
          validate: true,
        );
      } else {
        print("The OTP is not valid");
        return param;
      }
    } on SocketException {
      throw FetchDataException('message', 'url');
    } on TimeoutException {
      throw ApiNotRespondingException("message", "url");
    }
  }

我对上述 API 调用的 Classes 在这里:

class PhoneOTPValidate {
  PhoneOTPValidate({this.status, this.validate});
  final String? status;
  final bool? validate;
}

class UserRegistration {
  UserRegistration({this.key, this.status});
  final String? key;
  final bool? status;
}

Flutter 安全存储Class

class SecureStorage {
  final storage = FlutterSecureStorage();
  Future writeSecureToken(String key, String value) async {
    var writeData = await storage.write(key: key, value: value);
    print('Token Here');
    return writeData;
  }

  Future readSecureToken(String key) async {
    var readData = await storage.read(key: key);
    return readData;
  }

  Future deleteSecureToken(String key) async {
    var deleteData = await storage.delete(key: key);
    return deleteData;
  }
}

这是我所写内容的输出:

Response Body: {"key":"de18d1239ed0b6be13f4c9a9d96eebeb1c401922"}
I/flutter (23010): Token Here Instance of 'Future<dynamic>'
I/flutter (23010): Token Here

如何解决保存密钥并在其他 API 调用的 headers 中使用它的问题? 几乎尝试了 Whosebug 的所有解决方案,但没有一个能给出一个可靠的答案来说明它是如何完成的。 我在这个问题上停留了好几天 如果有人能根据我的代码解决我的问题,我将不胜感激。

问题是您没有“等待”读取和写入安全令牌。通过为您的变量提供显式类型,可以轻松避免这种情况。让我们修复您的代码:

// 我假设你正在使用 null-safety

class SecureStorage {
  final FlutterSecureStorage storage = FlutterSecureStorage();
  Future<void> writeSecureToken(String key, String value) async {
    // I'm not exactly sure how you get the data from storage.write, because it has a type of Future<void>
    // So the whole function should be await storage.write(key: key, value: value);
    await storage.write(key: key, value: value);
  }

  Future<String?> readSecureToken(String key) async {
    return await storage.read(key: key);
  }

  Future<void> deleteSecureToken(String key) async {
    // Same here: delete is a type of void, so it shouldn't return anything
    await storage.delete(key: key);
  }
}

然后安全存储更新完成后,我们可以开始获取令牌

final storage = SecureStorage();
Future<UserRegistration> registration(dynamic param) async {
  var client = http.Client();
  try {
    var response = await client
        .post(Uri.https("baseURL", "endpoint"), body: param)
        .timeout(Duration(seconds: TIME_CONST))
        .catchError(handleError);

    if (response.statusCode == 201) {
      print('Response Body: ${response.body}');
      final data = jsonDecode(response.body);

      ///////Using the flutter secure storage here to save the token
      String? token = data['key'];
      if (token == null) {
        throw Exception("No token in response");
      }
      
      await storage.writeSecureToken('key', token);
      print("Token Here $token");
      return UserRegistration(
        key: token,
        status: true,
      );
    } else {
      print("Something went wrong");
      return param;
    }
  } on SocketException {
    throw FetchDataException('message', 'url');
  } on TimeoutException {
    throw ApiNotRespondingException("message", "url");
  }
}

最后修复调用时对令牌的读取:

Future<PhoneOTPValidate> phoneOTPvalidate(dynamic param) async {
  var client = http.Client();
  // Added type String? on the left side and await keyword for the storage.read()
  String? token = await storage.readSecureToken('key');
  if (token == null) {
    throw Exception("No token stored in storage");
  }
  try {
    var response = await client
        .post(
          Uri.https("baseURL", "endpoint"),
          headers: <String, String>{
            'Authorization': 'Token $token',
          },
          body: param,
        )
        .timeout(Duration(seconds: TIME_CONST))
        .catchError(handleError);

    if (response.statusCode == 200) {
      print('Response Body: ${response.body}');
      final data = jsonDecode(response.body);
      return PhoneOTPValidate(
        status: data['success'],
        validate: true,
      );
    } else {
      print("The OTP is not valid");
      return param;
    }
  } on SocketException {
    throw FetchDataException('message', 'url');
  } on TimeoutException {
    throw ApiNotRespondingException("message", "url");
  }
}