Warm tip: This article is reproduced from serverfault.com, please click

reactjs-如果Apollo GraphQL令牌无效或已过期,则NextAuth.js注销

(reactjs - NextAuth.js signout if Apollo GraphQL token is invalid or it has expired)

发布于 2020-11-22 11:35:04

当尝试访问后端(Apollo GraphQL)并由于令牌已过期或无效而返回401时,清除NextAuth.js会话的最佳方法是什么?

我考虑了errorLinkand signout,但据我所知signout,不能在服务器端使用getServerSideProps,只能在客户端使用。

建议这样做的方法是什么?还有其他方法可以实现中间件来解决这种情况吗?

这将是errorLink我正在尝试实现的concepto的证明,其中包含了代码,if但是我不能使用它,signOut()因为它仅在客户端可用

const errorLink = onError(({ graphQLErrors }) => {
   if (graphQLErrors?.[0]?.message === 'Unauthenticated.') {
    // signOut();
  }
});

function createApolloClient(session) {
  return new ApolloClient({
    cache: new InMemoryCache(),
    ssrMode: typeof window === 'undefined',
    link: from([
      errorLink,
      createUploadLink({
        uri: GRAPHQL_URI,
        credentials: 'same-origin',
        headers: { Authorization: session?.accessToken ? `Bearer ${session.accessToken}` : '' },
      }),
    ]),
  });
}

谢谢

Questioner
VanPersie
Viewed
0
blacksoul 2020-12-01 17:13:11

正如Noah和Yog告诉你的那样,没有办法在服务器端执行此操作,因为signOut必须清除状态客户端。所以这就是我要做的:

function createApolloClient(session) {
  return new ApolloClient({
    cache: new InMemoryCache(),
    ssrMode: typeof window === 'undefined',
    link: from([
      createUploadLink({
        uri: GRAPHQL_URI,
        credentials: 'same-origin',
        headers: { Authorization: session?.accessToken ? `Bearer ${session.accessToken}` : '' },
      }),
    ]),
  });
}

然后,在你的getServerSiderProps

export const fetchServerSideProps = (
  initializeApollo: (context: SessionBase | null) => ApolloClient<NormalizedCacheObject>
): GetServerSideProps => async (context) => {
  const session = await getSession(context);
  const apolloClient = initializeApollo(session);
  try {
    // Fetch anything from GraphQL here

    return {
      props: {
        // add your required page props here
        session,
      },
    };
  } catch {
    // Token invalid or expired error (401) caught here, so let's handle this client-side.
    return { props: { session: null } };
  }
};

最后,你的页面如下所示:

const withAuth = <P extends { session: Session | null }>(Page: NextPage<P>) => (props: P): JSX.Element | null => {
  if (!props.session) {
    // Clear session and redirect to login
    signOut({ callbackUrl: '/login' });
    return null;
  }

  return <Page {...props} />;
};

const Page: NextPage<P> = (props) => (
  <p>This should be shown ONLY if the user is logged in</p>
); 

export default withAuth(LoggedInPage);