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,频繁的生物识别验证会严重影响用户体验。

总结到此!

相关推荐
晚霞的不甘2 小时前
Flutter for OpenHarmony 布局探秘:从理论到实战构建交互式组件讲解应用
开发语言·前端·flutter·正则表达式·前端框架·firefox·鸿蒙
运筹vivo@2 小时前
BUUCTF: [极客大挑战 2019]BabySQL
前端·web安全·php·ctf
Beginner x_u4 小时前
前端八股文 Vue下
前端·vue.js·状态模式
Easonmax10 小时前
零基础入门 React Native 鸿蒙跨平台开发:7——双向滚动表格实现
react native·react.js·harmonyos
Easonmax10 小时前
零基础入门 React Native 鸿蒙跨平台开发:6——竖向滚动表格实现
react native·react.js·harmonyos
提笔了无痕10 小时前
Web中Token验证如何实现(go语言)
前端·go·json·restful
戌中横11 小时前
JavaScript——Web APIs DOM
前端·javascript·html
Beginner x_u11 小时前
如何解释JavaScript 中 this 的值?
开发语言·前端·javascript·this 指针
HWL567911 小时前
获取网页首屏加载时间
前端·javascript·vue.js