Next-Auth:getServerSideProps调用的API中间件中getToken获AccessToken返回undefined
问题解答
这种情况是正常的,核心原因在于服务器端内部发起的HTTP请求不会自动携带用户的会话Cookie,而NextAuth的getToken函数正是依赖请求中的Cookie来解析出accessToken。
具体原因
当你在getServerSideProps里通过axios.get()调用自己的API路由时,这个请求是服务器到服务器的内部请求,并非来自用户浏览器。这类请求不会自动附带用户浏览器发送过来的NextAuth会话Cookie(比如next-auth.session-token)。而getServerSideProps能正常获取accessToken,是因为它直接接收了来自浏览器的完整请求,包含所有用户Cookie信息。
解决方案
针对这个问题,有两种常用的处理方式:
方案1:在getServerSideProps中获取Token,通过请求头传递给API路由
先在getServerSideProps中拿到accessToken,再通过请求头传递给API路由,避免API路由依赖Cookie获取Token。
修改pages/user.js:
import { getToken } from "next-auth/jwt"; function User({user_data, request_params}) { // ...组件逻辑 } export default User; export async function getServerSideProps( context ) { // 先在getServerSideProps中获取Token const token = await getToken({ req: context.req, secret: process.env.SECRET }); const user_data = await fetchUserData( context.query, token.accessToken ); return { props: { user_data: user_data, request_params: context.query } } } async function fetchUserData( params, accessToken ) { const ajax_url = 'http://localhost:3000/api/user/1/info'; let result; await axios.get(ajax_url, { headers: { // 将Token通过Authorization头传递 'Authorization': `Bearer ${accessToken}` } }) .then(response => { result = response.data; }).catch((error) => { // 原错误处理逻辑不变 if (error.response) { console.log('Error.response > Data: ', error.response.data); console.log('Error.response > Status: ', error.response.status); console.log('Error.response > Headers: ', error.response.headers); } else if (error.request) { console.log('Error.request: ', error.request); } else { console.log('Error: ', error.message); } console.log('Unknown Error: ', error.config); }); return result; }
修改api/user/[user]/info.js:
import axios from "axios"; export default async (req, res) => { // 从请求头中直接获取Token const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.status(401).json({ error: 'Unauthorized' }); } const accessToken = authHeader.split(' ')[1]; console.log('access token?: ' + accessToken); // 现在能正常获取到Token const config = { headers: { 'authorization': `Bearer ${accessToken}`, 'Cache-Control': 'no-cache', 'Pragma': 'no-cache', 'Expires': '0', } }; const ajax_url = `http://localhost/actualwebsite/public/api/v1/user/${req.query.user}/info`; await axios.get(ajax_url, config) .then(response => { res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Expires', '0'); res.status(200).json(response.data); }).catch((error) => { // 原错误处理逻辑不变 if (error.response) { console.log('Api > Error.response > Data: ', error.response.data); console.log('Api > Error.response > Status: ', error.response.status); console.log('Api > Error.response > Headers: ', error.response.headers); } else if (error.request) { console.log('Api > Error.request: ', error.request); } else { console.log('Api > Error: ', error.message); } console.log('Api > Unknown Error: ', error.config); }); }
方案2:直接在getServerSideProps中调用外部API(更高效)
跳过内部API路由,直接在getServerSideProps中完成外部API请求,减少一次服务器内部HTTP调用:
import { getToken } from "next-auth/jwt"; import axios from "axios"; function User({user_data, request_params}) { // ...组件逻辑 } export default User; export async function getServerSideProps( context ) { const token = await getToken({ req: context.req, secret: process.env.SECRET }); const { user } = context.query; const ajax_url = `http://localhost/actualwebsite/public/api/v1/user/${user}/info`; const config = { headers: { 'authorization': `Bearer ${token.accessToken}`, 'Cache-Control': 'no-cache', 'Pragma': 'no-cache', 'Expires': '0', } }; let user_data = null; try { const response = await axios.get(ajax_url, config); user_data = response.data; } catch (error) { // 错误处理逻辑 if (error.response) { console.log('Error.response > Data: ', error.response.data); console.log('Error.response > Status: ', error.response.status); console.log('Error.response > Headers: ', error.response.headers); } else if (error.request) { console.log('Error.request: ', error.request); } else { console.log('Error: ', error.message); } console.log('Unknown Error: ', error.config); } return { props: { user_data: user_data, request_params: context.query } } }
内容的提问来源于stack exchange,提问作者yeln
相关产品推荐
相关产品推荐

