You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Native中用react-native-keychain加密访问令牌并验证实现正确性

现有实现问题分析
  • 异步操作未处理:Keychain.setGenericPassword 为异步API,当前代码未加await也未处理Promise返回结果,存储失败时无法感知错误
  • 删除逻辑错误:removeItem 中调用Keychain.resetGenericPassword()会清空所有Keychain凭据,而非仅删除指定key对应的数据
  • 读取逻辑缺失:getItem仅从内存对象dataMemory读取,App重启后内存清空就无法获取历史存储的令牌,等于Keychain的持久化加密存储完全没有生效
  • 参数传递错误:sync方法中调用MyStorage.setItem仅传入了token值,缺少key参数,不符合方法定义的入参要求,无法正确存储数据
  • 冗余代码:导入的AsyncStorage未被使用,可以直接移除
修正后的参考实现
import * as Keychain from 'react-native-keychain';
import { Auth } from 'aws-amplify';

const MYSTORAGE_KEY_PREFIX = '@ACCESSTOKEN:';
let dataMemory = {};

export default class MyStorage {
  static syncPromise = null;

  // 改成异步方法,处理Keychain的异步操作
  static async setItem(key, value) {
    try {
      await Keychain.setGenericPassword(
        MYSTORAGE_KEY_PREFIX + key, 
        value,
        // 可选配置存储策略,比如设置生物认证、访问权限等
        { accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED }
      );
      dataMemory[key] = value;
      return dataMemory[key];
    } catch (e) {
      console.error('存储令牌失败', e);
      return null;
    }
  }

  static async getItem(key) {
    // 先读内存,内存没有再读Keychain
    if (Object.prototype.hasOwnProperty.call(dataMemory, key)) {
      return dataMemory[key];
    }
    try {
      const credentials = await Keychain.getGenericPassword({
        service: MYSTORAGE_KEY_PREFIX + key
      });
      if (credentials) {
        const { password } = credentials;
        dataMemory[key] = password;
        return password;
      }
      return undefined;
    } catch (e) {
      console.error('读取令牌失败', e);
      return undefined;
    }
  }

  static async removeItem(key) {
    try {
      // 只删除指定key对应的凭据
      await Keychain.resetGenericPassword({
        service: MYSTORAGE_KEY_PREFIX + key
      });
      delete dataMemory[key];
      return true;
    } catch (e) {
      console.error('删除令牌失败', e);
      return false;
    }
  }

  static clear() {
    dataMemory = {};
    // 清空所有对应前缀的Keychain数据可按需扩展实现
    return dataMemory;
  }
  
  static async sync(){
    if (!MyStorage.syncPromise) {
        MyStorage.syncPromise = new Promise(async (res, rej) => {
          try {
            const data = await Auth.currentSession();
            // 补全key参数,按Amplify存储规则设置对应key即可,示例用idToken作为key名
            await MyStorage.setItem('idToken', data.idToken.jwtToken);
            res(true);
          } catch (e) {
            rej(e);
          }
        });
    }
    return MyStorage.syncPromise;
  }
}

Auth.configure({
  storage: MyStorage
});
验证令牌加密的方法
  • 安卓端验证:打开Android Studio的Device File Explorer,进入/data/data/你的应用包名/目录,查找Keychain对应的存储文件,直接打开文件无法看到明文的令牌内容,均为加密后的乱码
  • iOS端验证:连接Xcode后进入「Devices and Simulators」,选择测试设备下载对应App的容器,打开容器内的Keychain存储数据,无法直接读取到明文令牌
  • 功能验证:
    1. 登录App获取令牌后杀掉App进程重新打开,无需重新登录即可获取到用户的登录状态,说明Keychain中加密存储的令牌可以被正常解密读取
    2. 编写测试代码直接读取App的本地存储文件,无法获取到明文令牌,只有通过react-native-keychain提供的API才能解密拿到明文内容,即代表加密生效

内容的提问来源于stack exchange,提问作者Test work

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 22:39:02