我正在使用 React 和 Next.js 开发一个 Web 应用程序,并且我还有一个作为后端分离的 Node.js API。
我有一个登录表单,我将数据发送到 API 以恢复 JWT,当我这样做时,一切正常,但在将用户重定向到受保护的路由“仪表板”后,或者刷新后,用户上下文会丢失。
这是受保护的路线:
import React, {useContext, useEffect} from 'react'
import { useRouter } from "next/router";
import { Context } from '../../context/context';
export default function DashboardIndexView() {
const router = useRouter();
const {isUserAuthenticated, setUserToken, userToken} = useContext(Context);
useEffect(() => {
isUserAuthenticated()
? router.push("/dashboard")
: router.push("/authentication/admin");
}, []);
return (
<>
<h1>Dashboard index view</h1>
</>
)
}
这是上下文文件:
import React, {createContext, useEffect, useState} from 'react'
import { useRouter } from "next/router";
import axios from 'axios'
export const Context = createContext(null)
const devURL = "http://localhost:4444/api/v1/"
export const ContextProvider = ({children}) => {
const router = useRouter()
const [user, setUser] = useState()
const [userToken, setUserToken] = useState()
const [loading, setLoading] = useState(false)
const [successMessage, setSuccessMessage] = useState("")
const [errorMessage, setErrorMessage] = useState("")
const Login = (em,pass) => {
setLoading(true)
axios.post(devURL+"authentication/login", {
email : em,
password : pass
})
.then((res)=>{
setSuccessMessage(res.data.message)
setErrorMessage(null)
setUser(res.data.user)
setUserToken(res.data.token)
localStorage.setItem('userToken', res.data.token)
localStorage.setItem('user', res.data.user)
setLoading(false)
})
.catch((err)=>{
setErrorMessage(err.response.data.message)
setSuccessMessage(null)
setLoading(false)
})
}
const Logout = () => {
setUserToken()
setUser()
localStorage.setItem('userToken', null)
localStorage.setItem('user', null)
router.push('/authentication/admin')
}
const isUserAuthenticated = () => !!userToken
return (
<Context.Provider value={{
Login,
user,
loading,
userToken,
setUserToken,
Logout,
successMessage,
setSuccessMessage,
setErrorMessage,
isUserAuthenticated,
errorMessage}}>
{children}
</Context.Provider>
)
}
即使发生刷新,如何让用户保持在仪表板页面上?
useContext()
在页面刷新时丢失其值是正常的。上下文不保存任何数据,它们只是在组件之间共享数据。在 Next.js 中,它可以在页面之间工作,因为 Next.js 处理客户端的导航。但正如您所注意到的,一旦刷新,应用程序就会从头开始安装,这一次上下文永远不会获取 JWT 的值,因为 JWT 从未在应用程序的这个新实例上发送。
从高层次来看,解决方案是将 JWT 存储在某个地方(localStorage 或 cookie)并将值注入到您的
Context.Provider
中。您已经在 localStorage 中设置了值,现在您只需要一个 useEffect
来读取它们并将它们添加到上下文中:
useEffect(() => {
setUser(localStorage.get('user'));
setUserToken(localStorage.get('userToken'));
}, []);
但在我看来,真正的解决方案是使用 https://next-auth.js.org/ 代替。它处理安全问题,是 Next.js 的知名库
为了避免本地存储未定义值,请使用此值。
const ISSERVER = typeof window === 'undefined'
useEffect(() => {
setUser(!ISSERVER && localStorage.get('user'));
setUserToken(!ISSERVER && localStorage.get('userToken'));
}, [])