React Native集成Laravel Sanctum时AsyncStorage无法持久化问题
React Native + Laravel Sanctum 认证问题修复方案
问题概述
在React Native应用中使用Laravel Sanctum API实现用户认证时,遇到以下问题:
- 登录时
useState的userInfo数据正确,但AsyncStorage存储的userInfo异常; - 重启应用后自动回到登录页,无法保持登录状态;
- 调用登出API时返回401未授权错误。
错误分析与修复步骤
一、AsyncStorage存储userInfo异常修复
错误原因:setUserInfo是异步状态更新操作,登录时直接用userInfo存储到AsyncStorage,此时userInfo还是初始的空数组/空值,导致存储数据异常。
修复代码:直接使用API返回的res.data进行存储:
// AuthContext.js 中login函数的修复片段 if (res.data.status === 200) { console.log(res.data) setUserInfo(res.data) // 用res.data替代未更新的userInfo状态 AsyncStorage.setItem("userInfo", JSON.stringify(res.data)); AsyncStorage.setItem("auth_token", res.data.token); AsyncStorage.setItem("auth_name", res.data.username); setIsLoading(false) }
二、重启应用无法保持登录修复
错误原因:应用重启时,AuthProvider的userInfo初始化为空值,未从AsyncStorage读取之前保存的用户数据,导致路由判断为未登录。
修复代码:在AuthProvider中添加useEffect,组件挂载时加载保存的用户信息:
// AuthContext.js 中添加以下代码 import { useEffect } from 'react'; export const AuthProvider = ({children}) => { // 初始化userInfo为null更合理,替代原数组初始化 const [userInfo, setUserInfo] = useState(null) const [isLoading, setIsLoading] = useState(false) // 加载本地保存的用户信息 useEffect(() => { const loadSavedUser = async () => { try { const savedUser = await AsyncStorage.getItem("userInfo"); const savedToken = await AsyncStorage.getItem("auth_token"); if (savedUser && savedToken) { setUserInfo(JSON.parse(savedUser)); } } catch (error) { console.error("加载用户信息失败:", error); } }; loadSavedUser(); }, []); // 原login、logout等逻辑保持(后续修复logout) }
三、Navigation中AsyncStorage使用错误修复
错误原因:AsyncStorage.getItem是异步函数,直接调用会返回Promise对象,无法直接用于路由判断;且路由判断应依赖context中的userInfo,无需直接读取AsyncStorage。
修复代码:
// Navigation.js 修复后 const Stack = createNativeStackNavigator(); const Navigation = () => { const { userInfo } = useContext(AuthContext); return ( <NavigationContainer> // 使用可选链操作符处理userInfo为null的情况 {userInfo?.username ? <AppStack /> : <AuthStack />} </NavigationContainer> ); };
四、登出401错误修复
1. Axios拦截器异步获取token错误
错误原因:AsyncStorage.getItem是异步函数,直接赋值会把Promise对象作为token,导致请求头Authorization无效,后端无法识别认证信息。
修复代码:
// App.js 中Axios拦截器修复 axios.interceptors.request.use(async function (config) { const token = await AsyncStorage.getItem("auth_token"); config.headers.Authorization = token ? `Bearer ${token}` : ""; return config; });
2. 登出逻辑不完整
错误原因:登出时未清除所有用户相关存储项,且原代码未使用async/await处理异步操作。
修复代码:
// AuthContext.js 中logout函数修复 const logout = async () => { setIsLoading(true) try { const res = await axios.post("/api/logout"); if (res.data.status === 200) { console.log(res.data) // 批量清除所有相关存储项 await AsyncStorage.multiRemove(["userInfo", "auth_token", "auth_name"]); setUserInfo(null); } } catch (e) { console.log(e) } finally { setIsLoading(false) } };
3. Laravel登出路由未添加认证中间件
错误原因:未给logout路由添加auth:sanctum中间件,导致后端无法识别登录用户,返回401。
修复代码:
// routes/api.php Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum');
完整认证流程
登录:
- 获取CSRF Cookie;
- 发送登录请求,验证成功后获取用户信息与token;
- 将用户信息、token存入AsyncStorage;
- 更新context状态,路由自动切换至仪表盘。
应用重启:
AuthProvider挂载时读取AsyncStorage中的用户数据;- 更新
userInfo状态,路由判断为已登录,直接进入仪表盘。
登出:
- 调用Laravel登出API,后端清除用户所有token;
- 清除AsyncStorage中所有用户相关数据;
- 重置
userInfo状态,路由切换至登录页。
内容的提问来源于stack exchange,提问作者motionless570
相关产品推荐
相关产品推荐

