React Native Expo + AWS Amplify实现离线登录功能方案咨询
基于React Native Expo + AWS Amplify Cognito实现离线认证方案
核心思路
AWS Amplify Cognito默认提供内存+本地缓存,但离线场景下需要更持久的凭证存储。结合你已使用的SQLite,核心逻辑是:联网时将Cognito返回的认证凭证(ID Token、Refresh Token、过期时间)存入SQLite;离线时读取本地存储的凭证,验证有效性后模拟Amplify的用户会话,实现离线登录;网络恢复时自动刷新凭证并更新本地存储。
一、前期依赖配置
确保项目已集成必要依赖:
expo install aws-amplify @aws-amplify/react-native expo-sqlite expo-network expo-secure-store
expo-secure-store用于加密存储敏感凭证(替代SQLite明文存token)expo-network用于检测网络状态
初始化Amplify Auth并配置Cognito(按官方流程完成,确保开启本地缓存)。
二、SQLite数据库初始化
创建用于存储认证信息的表,结合SecureStore加密敏感字段:
import * as SQLite from 'expo-sqlite'; import * as SecureStore from 'expo-secure-store'; // 初始化SQLite数据库 const db = SQLite.openDatabase('auth.db'); const initAuthDB = () => { db.transaction(tx => { tx.executeSql( 'CREATE TABLE IF NOT EXISTS user_auth (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE, expires_at INTEGER)' ); }); };
三、联网登录实现
调用Amplify Auth.signIn成功后,将凭证存入SQLite+SecureStore:
import { Auth } from 'aws-amplify'; const signInOnline = async (username, password) => { try { // 联网登录Cognito await Auth.signIn(username, password); const session = await Auth.currentSession(); const { idToken, refreshToken } = session; // 用SecureStore加密存储token await SecureStore.setItemAsync(`id_token_${username}`, idToken.jwtToken); await SecureStore.setItemAsync(`refresh_token_${username}`, refreshToken.token); // 非敏感信息存入SQLite db.transaction(tx => { tx.executeSql('REPLACE INTO user_auth (username, expires_at) VALUES (?, ?)', [ username, idToken.payload.exp * 1000 // 转成时间戳 ]); }); return session; } catch (err) { console.error('在线登录失败:', err); throw err; } };
四、联网登出实现
调用Amplify登出接口,同时清空本地存储的所有凭证:
const signOutOnline = async () => { try { await Auth.signOut(); // 获取本地存储的用户名,清空对应凭证 db.transaction(tx => { tx.executeSql('SELECT username FROM user_auth LIMIT 1', [], async (_, { rows }) => { if (rows.length > 0) { const username = rows.item(0).username; await SecureStore.deleteItemAsync(`id_token_${username}`); await SecureStore.deleteItemAsync(`refresh_token_${username}`); } tx.executeSql('DELETE FROM user_auth'); }); }); } catch (err) { console.error('在线登出失败:', err); throw err; } };
五、离线登录逻辑实现
检测网络状态,离线时读取本地凭证并验证有效性,模拟Amplify用户会话:
import * as Network from 'expo-network'; import { Cache } from 'aws-amplify'; const signInOffline = async () => { const networkState = await Network.getNetworkStateAsync(); if (networkState.isConnected) throw new Error('当前处于联网状态,请使用在线登录'); return new Promise((resolve, reject) => { db.transaction(tx => { tx.executeSql('SELECT * FROM user_auth LIMIT 1', [], async (_, { rows }) => { if (rows.length === 0) { reject(new Error('无本地登录凭证,请先联网登录')); return; } const { username, expires_at } = rows.item(0); const now = Date.now(); // 验证凭证是否过期 if (expires_at < now) { reject(new Error('本地凭证已过期,请联网重新登录')); return; } // 从SecureStore读取加密的token const idToken = await SecureStore.getItemAsync(`id_token_${username}`); const refreshToken = await SecureStore.getItemAsync(`refresh_token_${username}`); if (!idToken || !refreshToken) { reject(new Error('本地凭证损坏,请联网重新登录')); return; } // 构造Amplify兼容的用户会话,写入Amplify缓存 const mockSession = { username, signInUserSession: { idToken: { jwtToken: idToken }, refreshToken: { token: refreshToken } } }; await Cache.setItem('currentUser', mockSession); resolve(mockSession); }); }); }); };
六、网络恢复后的自动同步
监听网络状态变化,联网后自动刷新凭证并更新本地存储:
const setupNetworkSync = () => { Network.addNetworkStateListener(async state => { if (state.isConnected) await refreshAuthToken(); }); }; const refreshAuthToken = async () => { try { const session = await Auth.currentSession(); const newSession = await Auth.refreshSession(session.refreshToken); const { idToken, refreshToken } = newSession; const username = session.idToken.payload.username; // 更新本地存储 await SecureStore.setItemAsync(`id_token_${username}`, idToken.jwtToken); await SecureStore.setItemAsync(`refresh_token_${username}`, refreshToken.token); db.transaction(tx => { tx.executeSql('UPDATE user_auth SET expires_at = ? WHERE username = ?', [ idToken.payload.exp * 1000, username ]); }); } catch (err) { console.error('凭证刷新失败:', err); // 刷新失败需引导用户重新登录 } };
关键注意事项
- 凭证加密:必须用
expo-secure-store加密存储token,避免SQLite明文泄露敏感信息。 - 过期验证:离线登录时必须检查token过期时间,避免使用失效凭证。
- Amplify缓存兼容:模拟的用户会话要严格匹配Amplify的结构,确保后续
Auth.currentUserInfo()等方法能正常读取。 - 数据同步:如果应用有业务数据,建议搭配Amplify DataStore实现离线数据同步,与认证逻辑联动。
内容的提问来源于stack exchange,提问作者Amila
相关产品推荐
相关产品推荐

