Expo SecureStore在iOS生产环境丢失JWT令牌问题求助
我使用Expo的SecureStore存储JWT令牌,Android端运行正常,但iOS生产环境下令牌会突然丢失,用户需要重新登录。此前用AsyncStorage存储时也存在同样问题,查阅资料得知SecureStore通过keychain服务以kSecClassGenericPassword类型存储数据,安全性更高,但更换后iOS仍会删除令牌。
存储JWT的代码如下:
export const login = createAsyncThunk( "auth/login", async (userCredentials, thunkAPI) => { const notifToken = await SecureStore.getItemAsync("notification_token"); try { let loginData = { email: userCredentials.mail, password: userCredentials.password, }; if (notifToken) { loginData = { ...loginData, notif_token: notifToken, }; } const response = await axios.post(ENDPOINTS.loginToken, loginData, { headers: { "Content-Type": "application/json", }, }); await SecureStore.setItemAsync("access_token", response.data.access); await SecureStore.setItemAsync("refresh_token", response.data.refresh); return response.data; } catch (error) { await SecureStore.clear(); return thunkAPI.rejectWithValue(error.response.data); } } );
检查iOS keychain访问权限配置
iOS生产环境下,keychain访问权限需正确配置。在app.json中添加keychain权限组,替换为你的应用实际bundle ID:{ "expo": { "ios": { "entitlements": { "keychain-access-groups": ["$(AppIdentifierPrefix)com.your.app.bundle"] } } } }$(AppIdentifierPrefix)会自动填充开发者账号前缀,无需手动修改。修正
SecureStore.clear()的误触发
代码中登录失败的catch块调用了SecureStore.clear(),会清空所有存储内容。若登录请求因网络波动等原因偶尔失败,会直接删除已有的令牌。建议仅清除登录相关的令牌项:catch (error) { await SecureStore.deleteItemAsync("access_token"); await SecureStore.deleteItemAsync("refresh_token"); return thunkAPI.rejectWithValue(error.response.data); }指定令牌存储的访问属性
使用SecureStore.setItemAsync时,通过options参数明确keychain存储属性,设置accessible为SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY,降低系统自动清理概率:await SecureStore.setItemAsync("access_token", response.data.access, { accessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY }); await SecureStore.setItemAsync("refresh_token", response.data.refresh, { accessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY });该配置确保仅设备解锁时可访问令牌,且不会同步到iCloud。
排查iOS系统自动清理机制
iOS存储空间不足或用户开启“卸载未使用的应用”时,可能影响令牌存储。可提醒用户关闭自动卸载功能,同时在应用启动时检查令牌是否存在,若缺失则触发静默刷新(需有令牌刷新机制)。升级Expo SDK版本
部分旧版Expo SDK存在SecureStore相关bug,升级至最新稳定版可能解决问题。
内容的提问来源于stack exchange,提问作者Sahak 12

