React Native KeyChain完整封装

一、完整封装代码

javascript 复制代码
/**
 * @author Dragon Wu
 * @created 2026/01/20 14:04
 * @description KeyChain的封装
 */

import APP_ENV from '@/config/env';
import * as Keychain from 'react-native-keychain';

// === 安全存储函数(Keychain基础加密)===
export const saveSecure = async (
  key: string,
  value: unknown,
  options?: Keychain.SetOptions
): Promise<boolean> => {
  const data = typeof value === 'string' ? value : JSON.stringify(value);
  const result = await Keychain.setGenericPassword(key, data, {
    service: APP_ENV.keychainService,
    accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED,
    ...(options ?? {})
  });
  return !!result;
};

// 加载普通安全存储的数据
export const loadSecure = async <T = unknown>(key: string): Promise<T | null> => {
  const creds = await Keychain.getGenericPassword({ service: APP_ENV.keychainService });
  if (!creds || creds.username !== key) return null;

  try {
    return JSON.parse(creds.password);
  } catch {
    return creds.password as T;
  }
};

export const removeSecure = async (key: string): Promise<boolean> => {
  return await Keychain.resetGenericPassword({ service: key });
};

// === 生物识别存储函数(最高安全级别)===
export const saveWithBiometry = async (
  key: string,
  value: unknown,
  options?: Keychain.SetOptions
): Promise<boolean> => {
  const data = typeof value === 'string' ? value : JSON.stringify(value);
  const result = await Keychain.setGenericPassword(key, data, {
    service: APP_ENV.keychainService,
    accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED,
    accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_ANY,
    ...(options ?? {})
  });
  return result !== false;
};

// 加载生物识别存储的数据
export const loadWithBiometry = async <T = unknown>(
  key: string,
  promptOptions?: Keychain.AuthenticationPrompt
): Promise<T | null> => {
  const creds = await Keychain.getGenericPassword({
    service: APP_ENV.keychainService,
    authenticationPrompt: {
      title: '验证身份',
      cancel: '取消',
      ...(promptOptions ?? {})
    }
  });

  if (!creds || creds.username !== key) return null;

  try {
    return JSON.parse(creds.password);
  } catch {
    return creds.password as T;
  }
};

// 判断生物识别是否可用
export const isBiometryAvailable = async (): Promise<boolean> => {
  const type = await Keychain.getSupportedBiometryType();
  return type !== null;
};

// 清理所有keychain存储
export const clearAllCredentials = async (): Promise<void> => {
  await Keychain.resetGenericPassword();
};

Keychain 本地加密存储

使用文档

为什么需要 accessible 配置?

src\utils\storage\secureStorage.ts里默认配置了WHEN_UNLOCKED

accessible 选项 安全级别 适用场景
WHEN_UNLOCKED_THIS_DEVICE_ONLY 🔒🔒🔒🔒 最高 设备解锁后访问,不跨设备同步
WHEN_UNLOCKED 🔒🔒🔒 高 设备解锁后访问,可跨设备同步
AFTER_FIRST_UNLOCK 🔒🔒 中 首次解锁后即可访问
ALWAYS 🔒 低 随时可访问,包括设备锁定时
Token 类型 推荐配置 原因
access_token WHEN_UNLOCKED 平衡安全与体验,支持跨设备同步
refresh_token AFTER_FIRST_UNLOCK 允许后台刷新,避免频繁登录

生物识别安全存储

若需要使用生物识别安全存储功能,需开启以下权限配置

需要配置权限声明和最低系统版本。

📱 具体配置

iOS
  1. Info.plist 添加:
xml 复制代码
<key>NSFaceIDUsageDescription</key>
<string>App需要Face ID进行安全验证</string>
Android
  1. AndroidManifest.xml 添加:
xml 复制代码
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
  1. build.gradle 确保:
gradle 复制代码
minSdkVersion 23  // Android 6.0+

⚠️ 重要提醒

  • iOS:仅Face ID需要配置,Touch ID不需要
  • Android:从API 23(Android 6.0)开始支持
  • 模拟器:只能测试流程,无法真实验证

配置完这些,react-native-keychain的生物识别功能才能正常工作。

什么时候需要生物识别

access_token 直接用 Keychain 存储就够了,不需要生物识别。

📊 核心原因

场景 生物识别存储 Keychain普通存储 建议
每次请求API ❌ 需反复验证指纹/面容 ✅ 自动读取 Keychain
短期有效性 ⚠️ 过度保护(2小时过期) ✅ 风险可控 Keychain
实际安全需求 适合支付密码等 ✅ 已有设备级加密 Keychain

🎯 具体方案

typescript 复制代码
// ✅ 正确做法:普通Keychain存储
import { saveSecure } from './secureStorage';

// access_token - Keychain普通存储
await saveSecure('access_token', 'eyJhbGciOiJ...');

// refresh_token - 也可Keychain存储
await saveSecure('refresh_token', 'refresh_xyz');

生物识别留给真正的敏感数据:

  • 银行卡PIN码
  • 生物特征密钥
  • 医疗健康数据

Keychain的加密已经足够保护 token,频繁的生物识别验证会严重影响用户体验。

总结到此!

相关推荐
于慨17 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz17 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
从前慢丶17 小时前
前端交互规范(Web 端)
前端
@yanyu66617 小时前
07-引入element布局及spring boot完善后端
javascript·vue.js·spring boot
CHU72903518 小时前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing18 小时前
Page-agent MCP结构
前端·人工智能
王霸天18 小时前
💥别再抄网上的Scale缩放代码了!50行源码教你写一个永不翻车的大屏适配
前端·vue.js·数据可视化
小领航18 小时前
用 Three.js + Vue 3 打造炫酷的 3D 行政地图可视化组件
前端·github
@大迁世界18 小时前
2026年React大洗牌:React Hooks 将迎来重大升级
前端·javascript·react.js·前端框架·ecmascript
PieroPc18 小时前
一个功能强大的 Web 端标签设计和打印工具,支持服务器端直接打印到局域网打印机。Fastapi + html
前端·html·fastapi