如何在React Native应用中无提示刷新Apple登录并更新Azure App Service登录
无提示刷新Apple登录令牌(Expo + Azure App Service)
核心问题分析
你当前的困境源于两个关键误区:
- 未正确获取并使用Apple登录返回的refreshToken
- 调用Azure App Service的
/.auth/refresh时使用了错误的凭证(用了id_token或access_token而非Azure返回的refresh_token)
正确实现步骤
1. 首次登录时完整保存凭证信息
调用AppleAuthentication.signInAsync成功后,除了identityToken,还要保存refreshToken(Apple提供的刷新令牌),以及Azure App Service登录接口返回的refresh_token(注意区分Apple的refreshToken和Azure的refresh_token)。
修改登录代码,确保保存所有必要凭证:
const credential = await AppleAuthentication.signInAsync({ requestedScopes: [ AppleAuthentication.AppleAuthenticationScope.FULL_NAME, AppleAuthentication.AppleAuthenticationScope.EMAIL, ], }); // 保存Apple的refreshToken到本地安全存储(推荐用expo-secure-store替代AsyncStorage) await SecureStore.setItemAsync('appleRefreshToken', credential.refreshToken); // 调用Azure登录接口 const azureLoginResponse = await fetch('https://myapi.azurewebsites.net/.auth/login/apple', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id_token: credential.identityToken }), }); const azureAuthData = await azureLoginResponse.json(); // 保存Azure返回的access_token和refresh_token await SecureStore.setItemAsync('azureAccessToken', azureAuthData.access_token); await SecureStore.setItemAsync('azureRefreshToken', azureAuthData.refresh_token);
2. 无提示刷新Apple令牌(解决Expo refreshAsync问题)
AppleAuthentication.refreshAsync需要传入有效的refreshToken,iOS平台下只要用户未取消App授权,就能无提示完成刷新。你之前返回无效结果大概率是未正确传入refreshToken。
正确调用方式:
const savedAppleRefreshToken = await SecureStore.getItemAsync('appleRefreshToken'); if (!savedAppleRefreshToken) { // 无刷新令牌,引导用户重新登录 return; } try { const newCredential = await AppleAuthentication.refreshAsync({ refreshToken: savedAppleRefreshToken, }); // 更新本地存储的Apple凭证 await SecureStore.setItemAsync('appleIdentityToken', newCredential.identityToken); // 若返回新的refreshToken则更新,否则保留原token if (newCredential.refreshToken) { await SecureStore.setItemAsync('appleRefreshToken', newCredential.refreshToken); } } catch (error) { // 刷新失败(比如用户取消授权),引导重新登录 console.error('Apple token refresh failed:', error); }
3. 正确调用Azure App Service的令牌刷新接口
Azure的/.auth/refresh接口必须使用Azure返回的refresh_token,且需用POST请求:
const savedAzureRefreshToken = await SecureStore.getItemAsync('azureRefreshToken'); if (!savedAzureRefreshToken) { return; } try { const refreshResponse = await fetch('https://myapi.azurewebsites.net/.auth/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh_token: savedAzureRefreshToken }), }); if (refreshResponse.ok) { const newAzureAuthData = await refreshResponse.json(); // 更新本地存储的Azure凭证 await SecureStore.setItemAsync('azureAccessToken', newAzureAuthData.access_token); if (newAzureAuthData.refresh_token) { await SecureStore.setItemAsync('azureRefreshToken', newAzureAuthData.refresh_token); } } else { // Azure刷新失败,尝试用最新的Apple identityToken重新登录Azure const newAppleIdentityToken = await SecureStore.getItemAsync('appleIdentityToken'); if (newAppleIdentityToken) { const reLoginResponse = await fetch('https://myapi.azurewebsites.net/.auth/login/apple', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id_token: newAppleIdentityToken }), }); if (reLoginResponse.ok) { const newAzureAuthData = await reLoginResponse.json(); await SecureStore.setItemAsync('azureAccessToken', newAzureAuthData.access_token); await SecureStore.setItemAsync('azureRefreshToken', newAzureAuthData.refresh_token); } else { // 彻底失败,引导用户重新登录 } } } } catch (error) { console.error('Azure token refresh failed:', error); }
4. 自动刷新时机
建议在以下场景触发刷新:
- App启动时,检查Azure access_token的过期时间,若剩余时长不足1小时则触发刷新
- 调用API返回401 Unauthorized时,自动尝试刷新令牌,刷新成功后重试API请求
关键注意事项
- Apple的refreshToken有效期较长,但用户若在Apple设置中取消App授权,刷新会直接失败
- Azure的refresh_token也有有效期,若Azure刷新失败,需用最新的Apple identityToken重新登录
- 所有敏感凭证必须加密存储,禁止用明文AsyncStorage,优先使用
expo-secure-store
内容的提问来源于stack exchange,提问作者user14002075
相关产品推荐
相关产品推荐

