如何在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存储数据,无法直接读取到明文令牌
- 功能验证:
- 登录App获取令牌后杀掉App进程重新打开,无需重新登录即可获取到用户的登录状态,说明Keychain中加密存储的令牌可以被正常解密读取
- 编写测试代码直接读取App的本地存储文件,无法获取到明文令牌,只有通过
react-native-keychain提供的API才能解密拿到明文内容,即代表加密生效
内容的提问来源于stack exchange,提问作者Test work
相关产品推荐
相关产品推荐

