React全局Auth状态重定向后变为undefined的问题求助
React全局Auth状态重定向后变为undefined的问题求助
大家好,我正在用React开发一个聊天应用,最近在认证逻辑上碰到了棘手的问题:登录成功后我把accessToken存在了全局的auth状态里,但重定向到聊天页面后,这个auth状态居然变成undefined了!
具体情况是这样的:登录成功后,我通过后端接口能确认已经登录成功,console.log也能看到auth状态更新了:
Updated auth: {accessToken: 'eyJhb......_ucf70'}
可一旦重定向到聊天页面,调用获取聊天记录的接口时就返回401 Unauthorized错误,这明显是auth里的accessToken丢失了——我在useAxiosPrivate.js里打了日志,显示:
this is the auth undefined
下面是我相关的代码片段,麻烦大家帮我排查一下问题所在:
Login.jsx
//... other imports import axios from '../api/axios'; import useAuth from '../hooks/useAuth'; //...(rest of code) import { Link, useNavigate, useLocation } from 'react-router-dom'; const LOGIN_URL = '/login'; const Login = () => { const { auth, setAuth } = useAuth() const navigate = useNavigate() const location = useLocation() const from = location.state?.from?.pathname || "/chat" const [user, setUser] = useState(''); const [pwd, setPwd] = useState(''); const [errMsg, setErrMsg] = useState(''); useEffect(() => { userRef.current.focus(); }, []); useEffect(() => { setErrMsg(''); }, [user, pwd]); useEffect(() => { console.log("Updated auth:", auth); }, [auth]); useEffect(() => { if(auth && auth.accessToken){ navigate('/chat', { replace: true }); } }, [auth, navigate]); const handleSubmit = async (e) => { e.preventDefault(); const formData = new FormData(); formData.append('username', user); formData.append('password', pwd); try { const response = await axios.post( LOGIN_URL, formData, { headers: { 'Content-Type': 'multipart/form-data' }, withCredentials: true, } ); console.log(JSON.stringify(response?.data)); const accessToken = response?.data.access_token; setAuth({accessToken}) setUser(''); setPwd('') setErrMsg(''); } catch (err) { if (!err?.response) { //setErrMsg('No Server Response'); removing for now console.log(err); } else if (err.response?.status === 400) { setErrMsg('Missing Username or Password'); } else if (err.response?.status === 401) { setErrMsg('Unauthorized'); } else { console.log(err); setErrMsg('Login Failed'); } errRef.current.focus(); } }; return ( // JSX for login ) } export default Login
ChatPage.jsx
//... other imports import { useState, useEffect, useRef } from "react"; import useRefreshToken from "../hooks/useRefreshToken"; import useAxiosPrivate from "../hooks/useAxiosPrivate"; const ChatPage = () => { const axiosPrivate = useAxiosPrivate(); const refresh = useRefreshToken(); //... unrelated code useEffect(() => { const fetchChats = async () => { try { const response = await axiosPrivate.get('/chat/getchats'); if (response.status === 200) { setChats(response.data.map(chat => chat.chat_name)); } else { console.error("Error fetching the chats:", response.data); } } catch (error) { console.error("There was a problem fetching chats:", error); } }; fetchChats(); }, []); // Empty dependency array ensures this useEffect runs only once //... rest of ChatPage component }
axios.js
import axios from "axios" const BASE_URL ='http://127.0.0.1:8000' export default axios.create({ baseURL: BASE_URL }) export const axiosPrivate = axios.create({ baseURL: BASE_URL, headers: {"Content-Type": "application/json"}, withCredentials:true })
AuthProvider.jsx
import { createContext, useState } from "react"; const AuthContext = createContext({}); export const AuthProvider = ({ children }) => { const [auth, setAuth] = useState({}); return ( <AuthContext.Provider value={{ auth, setAuth }}> {children} </AuthContext.Provider> ) } export default AuthContext;
useAuth.jsx
import { useContext } from "react"; import AuthContext from "../context/AuthProvider"; const useAuth = () => { const { auth } = useContext(AuthContext); return useContext(AuthContext); } export default useAuth;
useAxiosPrivate.jsx
import { axiosPrivate } from "../api/axios"; import { useEffect } from "react"; import useRefreshToken from "./useRefreshToken"; import useAuth from "./useAuth"; const useAxiosPrivate = () => { const refresh = useRefreshToken(); const { auth } = useAuth(); useEffect(() => { console.log(`this is the auth ${auth.AccessToken}`) const requestIntercept = axiosPrivate.interceptors.request.use( config => { if (!config.headers['Authorization']){ config.headers['Authorization'] = `Bearer ${auth.AccessToken}`; } return config; }, (error) => Promise.reject(error) ) const responseIntercept = axiosPrivate.interceptors.response.use( response => response, async (error) => { const prevRequest = error?.config; if (error?.response?.status ===403 && !prevRequest?.sent) { prevRequest.sent = true; const newAccessToken = await refresh() prevRequest.headers['Authorization'] = `Bearer ${newAccessToken}`; return axiosPrivate(prevRequest); } return Promise.reject(error); } ) return () => { axiosPrivate.interceptors.request.eject(requestIntercept) axiosPrivate.interceptors.response.eject(responseIntercept) } },[auth, refresh]) return axiosPrivate; } export default useAxiosPrivate;
App.jsx
import {BrowserRouter, Routes, Route} from "react-router-dom" import HomePage from "./components/HomePage" import ChatPage from "./components/ChatPage" import SignUp from "./components/SignUp" import Login from "./components/Login" import Layout from "./components/Layout" import RequireAuth from "./components/RequireAuth" function App() { return ( <Routes> <Route path="/" element={<Layout />}> <Route path='/' element = {<HomePage/>} /> <Route path='/login' element = {<Login/>} /> <Route path='/signup' element = {<SignUp/>} /> {/* this is a protected route */} <Route element = {<RequireAuth />} > <Route path='/chat' element = {<ChatPage/>} /> </Route> </Route> </Routes> ) } export default App;
main.jsx
import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import { Route, Routes } from 'react-router-dom'; import { AuthProvider } from './context/AuthProvider'; import { ThemeProvider } from '@material-tailwind/react'; import { BrowserRouter } from 'react-router-dom'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <ThemeProvider> <BrowserRouter> <AuthProvider> <Routes> <Route path="/*" element={<App />} /> </Routes> </AuthProvider> </BrowserRouter> </ThemeProvider> </React.StrictMode> );
备注:内容来源于stack exchange,提问作者Rodrigo Burberg
相关产品推荐
相关产品推荐

