Next.js登录成功后如何将JWT Token传递至/allcoupons页面?
问题描述
我正在开发一个登录应用,前端使用Next.js,后端使用SpringBoot。已实现前端登录功能,调用SpringBoot的/authenticate接口成功返回authToken,目前将其存储在localStorage中,之后跳转到首页/allcoupons。
首页需要展示通过后端另一接口获取的优惠券列表,但该接口调用在getServerSideProps()中,无法访问localStorage里的authToken,导致无法在请求中携带令牌。请问如何将authToken传递至首页的getServerSideProps()中?
解决方案
方案1:使用Cookie存储Token(推荐)
服务端渲染时,getServerSideProps可以访问请求头中的Cookie,因此将Token存在Cookie中是最安全且适配服务端渲染的方案。
修改login.js:
- 安装
js-cookie库简化Cookie操作:
npm install js-cookie
- 导入并替换localStorage存储逻辑:
import Cookies from 'js-cookie'; // ... 其他代码 const handleSubmit = async (e) => { // ... 其他代码 try { const response = await axios({ method: "post", headers: {}, url: "http://localhost:8081/authenticate", data: requestbody, }); if (response.status === 200){ // 替换localStorage为Cookie存储,设置过期时间、安全属性 Cookies.set('authToken', response.data, { expires: 7, secure: process.env.NODE_ENV === 'production', sameSite: 'strict' }); router.push("/allcoupons"); } else { alert("invalid credentials") } } catch (error) { // ... 错误处理 } };
修改home.js的getServerSideProps:
从请求头的Cookie中提取Token:
export async function getServerSideProps(context) { let authToken = ''; // 从请求头获取Cookie并解析 if (context.req.headers.cookie) { const cookieMap = context.req.headers.cookie.split(';').reduce((acc, cookie) => { const [key, value] = cookie.trim().split('='); acc[key] = value; return acc; }, {}); authToken = cookieMap.authToken || ''; } const res = await axios.get(`http://localhost:8081/couponstore/v1.0/coupons`, { headers: {"Authorization": `Bearer ${authToken}`} }) const datafromAPI = res.data return { props: { datafromAPI } } }
方案2:URL参数传递Token(不推荐,仅用于测试)
通过跳转时的URL参数传递Token,此方法存在安全风险(Token会暴露在URL中),生产环境禁止使用。
修改login.js的跳转逻辑:
if (response.status === 200){ localStorage.setItem("authToken", response.data); // 通过query参数传递Token router.push({ pathname: '/allcoupons', query: { token: response.data } }); }
修改home.js的getServerSideProps:
export async function getServerSideProps(context) { const authToken = context.query.token || ''; // 拿到Token后建议立刻存入Cookie/localStorage,并重定向移除URL参数 if (authToken) { return { redirect: { destination: '/allcoupons', permanent: false } } } const res = await axios.get(`http://localhost:8081/couponstore/v1.0/coupons`, { headers: {"Authorization": `Bearer ${authToken}`} }) const datafromAPI = res.data return { props: { datafromAPI } } }
方案3:客户端获取数据(放弃服务端渲染)
将数据请求从getServerSideProps移到客户端组件中,直接访问localStorage中的Token,但会失去服务端渲染的SEO优势。
修改home.js:
移除getServerSideProps,改用useEffect在客户端请求数据:
const Allcoupons = () => { const router = useRouter(); const [data, setData] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { const fetchCoupons = async () => { const authToken = localStorage.getItem("authToken"); // 无Token则跳回登录页 if (!authToken) { router.push('/login'); return; } try { const res = await axios.get(`http://localhost:8081/couponstore/v1.0/coupons`, { headers: {"Authorization": `Bearer ${authToken}`} }); setData(res.data.coupons); } catch (error) { console.error('获取优惠券失败', error); } finally { setLoading(false); } }; fetchCoupons(); }, [router]); if (loading) { return <div>加载中...</div>; } // 原组件渲染逻辑,将data替换为state中的data return ( <> <section className={`text-gray-600 body-font ${(showModal || showstatusModal) ? "bg-slate-800/10" : ""} banner02 fadeRightMini`}> <div className="container px-5 py-24 mx-auto"> <div className="flex flex-col text-center w-full mb-20"> {/* ... 原内容 */} </div> <div className="lg:w-10/12 w-full mx-auto overflow-auto"> <table className="table-auto w-full text-center whitespace-no-wrap"> <thead> <tr> {/* ... 原内容 */} </tr> </thead> <tbody> {data.map((item) => ( // ... 原渲染逻辑 ))} </tbody> </table> </div> </div> </section> <Footer /> </> ); }; export default Allcoupons;
总结
优先选择方案1,既保留服务端渲染的优势,又能安全地在服务端获取Token;如果对SEO没有要求,方案3实现最简单;方案2仅适合临时测试,绝对不能用于生产环境。
内容的提问来源于stack exchange,提问作者MagnusEffect
相关产品推荐
相关产品推荐

