You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js SSR项目中GraphQL认证请求头传递失败求助

问题

在SSR的Next.js项目中为GraphQL添加认证机制,需要仅允许已认证用户发起请求,但尝试在Authorization请求头中传递用户ID时失败。试过通过Firebase getAuth().currentUser 获取UID,也试过从Redux Store的getState()获取,但都无法成功传递信息。相关代码如下:

import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { getAuth } from 'firebase/auth';
const httpLink = createHttpLink({
    uri: 'http://localhost:4000/graphql',
});

const authLink = setContext((_, { headers }) => {
    const user = getAuth().currentUser;
    return {
        headers: {
            ...headers,
            authorization: user?.uid ?? "null"
        }
    }
})
const client = new ApolloClient({
    link: authLink.concat(httpLink),
    cache: new InMemoryCache()
});


export default client;

解决方案

Firebase Auth在SSR里拿不到用户的原因及解决办法

在SSR环境下,getAuth().currentUser 是客户端异步加载的,你初始化Apollo Client的时候,Firebase还没完成用户会话的加载,所以肯定拿不到值。得换个方式:

  • 用Next.js的getServerSideProps或者getInitialProps在页面渲染前提前获取用户的ID Token(别直接传UID,不安全),再把token传给Apollo Client。
    比如在页面或者_app.js里写:
    export async function getServerSideProps(context) {
      const auth = getAuth();
      const user = auth.currentUser;
      let token = null;
      if (user) {
        token = await user.getIdToken();
      }
      return {
        props: { token }, // 把token传给页面组件
      };
    }
    
    然后把Apollo Client改成工厂函数,接收token参数:
    export function createApolloClient(token) {
      const httpLink = createHttpLink({
        uri: 'http://localhost:4000/graphql',
      });
    
      const authLink = setContext((_, { headers }) => ({
        headers: {
          ...headers,
          authorization: token ? `Bearer ${token}` : "null",
        },
      }));
    
      return new ApolloClient({
        link: authLink.concat(httpLink),
        cache: new InMemoryCache(),
      });
    }
    
    最后在_app.js里用这个函数创建客户端:
    import { ApolloProvider } from '@apollo/client';
    import { createApolloClient } from '../lib/apollo-client';
    
    function MyApp({ Component, pageProps, token }) {
      const client = createApolloClient(token);
      return (
        <ApolloProvider client={client}>
          <Component {...pageProps} />
        </ApolloProvider>
      );
    }
    
    export async function getServerSideProps(context) {
      const auth = getAuth();
      const user = auth.currentUser;
      let token = null;
      if (user) {
        token = await user.getIdToken();
      }
      return {
        props: { token },
      };
    }
    
    export default MyApp;
    

Redux Store拿不到用户ID的问题

你从Redux Store的getState()拿不到用户ID,大概率是Apollo Client初始化的时机比Redux Store早,或者SSR里Redux状态还没完成hydrate。解决办法和上面类似:在_app.js里先拿到Redux的用户ID,再传给Apollo Client的创建函数,确保获取到的是最新的状态。

额外提醒

  • 服务器端别直接信任Authorization头里的UID,得验证token的合法性(比如用Firebase Admin SDK验证ID Token),防止伪造请求。
  • 如果是静态生成(SSG)的页面,没法在服务器端拿用户会话,就得在客户端等Firebase Auth加载完成后再设置授权头:
    const authLink = setContext(async (_, { headers }) => {
      const user = await new Promise((resolve) => {
        const unsubscribe = getAuth().onAuthStateChanged((user) => {
          unsubscribe();
          resolve(user);
        });
      });
      const token = user ? await user.getIdToken() : null;
      return {
        headers: {
          ...headers,
          authorization: token ? `Bearer ${token}` : "null",
        },
      };
    });
    

内容的提问来源于stack exchange,提问作者Nahuel Luna Garcia Soaje

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:42:51