如何持久化NextAuth用户会话?解决刷新页面用户数据丢失问题
问题:登录后刷新/home页面,用户数据变为null
我需要实现用户登录后存储返回的用户数据(包含用于其他路由获取数据的ID),登录成功后跳转至/home路由,使用会话中的ID获取数据。初始状态下一切正常,但刷新/home页面后,user变为null。
[...nextauth].js 代码
import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import axios from "axios"; export default NextAuth({ providers: [ CredentialsProvider({ name: "credentials", credentials: { username: { label: "Username", type: "text", placeholder: "justin" }, password: {label: "Password",type: "password",placeholder: "******"}, }, async authorize(credentials, req) { const url = req.body.callbackUrl.split("/auth")[0]; const { username, password } = credentials; const user = await axios({ url: `${url}/api/user/login`, method: "POST", data: { username: username, password: password, }, "content-type": "application/json", }) .then((res) => { return res.data; }) .catch((err) => { if (err.response.data) { throw new Error(err.response.data); } else { return null; } return null; }); return user; }, }), ], callbacks: { jwt: ({ token, user }) => { if (user) { token.user = user; } return token; }, session: ({ session, token }) => { if (token) { session.user = token.user; } return session; }, }, pages: { signIn: "/auth/login", newUser: "/auth/register", }, });
/home 路由代码
import Card from "@/components/card/Card"; import React, { useEffect, useState } from "react"; import styles from "./home.module.css"; import { Ubuntu } from "@next/font/google"; import { useSession } from "next-auth/react"; import { useDispatch, useSelector } from "react-redux"; const ubuntu = Ubuntu({ weight: "500", subsets: ["cyrillic"] }); const getData = async (id) => { const res = await fetch({ url: "http://localhost:3000/api/note/getall", method: "POST", "content-type": "application/json", data: { id: id, }, }); if (!res.ok) { console.log(id); throw new Error("Unable to fetch"); } else { return res.json(); console.log(res); } }; function home() { const colors = ["#E9F5FC", "#FFF5E1", "#FFE9F3", "#F3F5F7"]; const random = Math.floor(Math.random() * 5); const rc = colors[random]; const [pop, setPop] = useState("none"); const { user } = useSelector((state) => state.user); const getDataa = async () => { console.log(user) const data = await getData(user._id); console.log(data); }; useEffect(() => { if (user) { alert(user) } }, []); return ( <div className={styles.home}> <header> <h3 className={ubuntu.className}> Hello, <br /> {user?.username}! </h3> <input type="text" placeholder="search" /> </header> <div className={styles.nav}> <h1 className={ubuntu.className}>Notes</h1> </div> <div className={styles.section}> <div className={styles.inner}> {/* {data && data.map((e) => ( <Card rawData={e} color={colors[Math.floor(Math.random() * colors.length)]} /> ))} */} </div> </div> <div className="new"></div> </div> ); } export default home;
解决方案
问题根源
- Redux状态丢失:Redux是内存状态管理,页面刷新后状态会重置,直接从Redux取
user会导致刷新后数据为空。 - 未正确依赖NextAuth会话:虽引入
useSession但未实际使用,也未将会话数据同步到Redux。 - fetch用法错误:
getData中fetch参数格式错误,会导致请求失败。
具体修复步骤
1. 修正Home组件,正确使用NextAuth会话
import Card from "@/components/card/Card"; import React, { useEffect, useState } from "react"; import styles from "./home.module.css"; import { Ubuntu } from "@next/font/google"; import { useSession } from "next-auth/react"; import { useDispatch, useSelector } from "react-redux"; const ubuntu = Ubuntu({ weight: "500", subsets: ["cyrillic"] }); // 修复fetch参数格式 const getData = async (id) => { const res = await fetch("http://localhost:3000/api/note/getall", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ id: id }), }); if (!res.ok) { console.log(id); throw new Error("Unable to fetch"); } return res.json(); }; function Home() { const colors = ["#E9F5FC", "#FFF5E1", "#FFE9F3", "#F3F5F7"]; const [pop, setPop] = useState("none"); const { data: session, status } = useSession(); const dispatch = useDispatch(); const reduxUser = useSelector((state) => state.user); // 会话加载完成后同步到Redux useEffect(() => { if (status === "authenticated" && session?.user) { dispatch({ type: "SET_USER", payload: session.user }); // 替换为你的Redux更新action } }, [session, status, dispatch]); const currentUser = reduxUser || session?.user; const getDataa = async () => { if (!currentUser) return; try { const data = await getData(currentUser._id); console.log(data); } catch (err) { console.error(err); } }; useEffect(() => { if (currentUser) { getDataa(); } }, [currentUser]); // 处理加载状态 if (status === "loading") { return <div>加载中...</div>; } // 未登录跳转登录页 if (status === "unauthenticated") { window.location.href = "/auth/login"; return null; } return ( <div className={styles.home}> <header> <h3 className={ubuntu.className}> Hello, <br /> {currentUser?.username}! </h3> <input type="text" placeholder="search" /> </header> <div className={styles.nav}> <h1 className={ubuntu.className}>Notes</h1> </div> <div className={styles.section}> <div className={styles.inner}> {/* {data && data.map((e) => ( <Card rawData={e} color={colors[Math.floor(Math.random() * colors.length)]} /> ))} */} </div> </div> <div className="new"></div> </div> ); } export default Home;
2. 完善NextAuth配置
在[...nextauth].js中添加会话密钥,确保JWT持久化:
import process from "process"; import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import axios from "axios"; export default NextAuth({ secret: process.env.NEXTAUTH_SECRET, // 从.env.local获取,可用openssl rand -hex 32生成 providers: [/* 现有代码 */], callbacks: [/* 现有代码 */], pages: [/* 现有代码 */], });
在.env.local中添加NEXTAUTH_SECRET=生成的随机字符串。
3. 全局配置SessionProvider(可选)
在_app.js中添加会话提供者,确保全应用可访问会话:
import { SessionProvider } from "next-auth/react"; export default function App({ Component, pageProps: { session, ...pageProps } }) { return ( <SessionProvider session={session}> <Component {...pageProps} /> </SessionProvider> ); }
核心逻辑说明
- 刷新页面后,NextAuth会从Cookie恢复会话,
useSession会先进入loading状态,加载完成后返回用户数据。 - 通过
useEffect监听会话变化,将数据同步到Redux,保证状态一致性。 - 修复fetch参数错误,使用标准的POST请求格式发送数据。
内容的提问来源于stack exchange,提问作者crayonne
相关产品推荐
相关产品推荐

