将 Next.js 更新到 React 18 使用 next-auth 破坏了我的 API 调用

问题描述 投票:0回答:1

这很奇怪,但情况是这样的。

我使用 Next.js 和 Next-auth 包来处理身份验证。

我没有使用服务器端渲染,它是一个管理区域,因此不需要 SSR,并且为了对用户进行身份验证,我创建了一个 HOC 来包装除“/sign-in”之外的基本上所有组件“路线。

这个 HOC 所做的就是检查是否有会话,然后将“访问令牌”添加到 Axios 实例,以便将其用于所有异步调用,如果没有会话,它将用户重定向到“登录” “这样的页面...

const AllowAuthenticated = (Component: any) => {
  const AuthenticatedComponent = () => {
    const { data: session, status }: any = useSession();
    const router = useRouter();

    useEffect(() => {
      if (status !== "loading" && status === "unauthenticated") {
        axiosInstance.defaults.headers.common["Authorization"] = null;
        signOut({ redirect: false });
        router.push("/signin");
      } else if (session) {
        axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${session.accessToken.accessToken}`;
      }
    }, [session, status]);

    if (status === "loading" || status === "unauthenticated") {
      return <LoadingSpinner />;
    } else {
      return <Component />;
    }
  };

  return AuthenticatedComponent;
};

export default AllowAuthenticated;

在 Axios 实例中,我检查响应是否为“401”,然后注销用户并将其发送到“登录”屏幕,如下所示...

axiosInstance.interceptors.response.use(
  response => response,
  error => {
    const { status } = error.response;
    if (status === 401) {
      axiosInstance.defaults.headers.common["Authorization"] = null;
      signOut({ redirect: false });
      return Promise.reject(error);
    }
    return Promise.reject(error);
  },
);

非常简单的东西,它就像一个魅力,直到我决定升级我的项目以使用“react 18.1.0”和“react-dom 18.1.0”,然后突然间,我的API调用没有得到“授权”标头,它们返回“401”并且用户被注销:(

如果我在设置 Auth 标头后立即尝试在 HOC 内进行 API 调用,那么我确实会从会话中获取“令牌”,但包装组件内的所有异步调度调用都会返回 401。

我忘了提到,这个问题发生在页面刷新时,如果我登录后没有刷新页面,一切都很好,但是一旦刷新页面,内部异步调度调用就会返回 401。

我更新了项目中的所有包,包括 Axios 和 next-auth,但没有帮助。

我最终不得不降级回“react 17.0.2”,一切又恢复正常了。

非常感谢任何帮助。

reactjs authentication next.js axios next-auth
1个回答
2
投票

对于那些可能遇到同样问题的人。

我设法通过不包含将令牌添加到 HOC 内的“Authorization”标头的逻辑来解决这个问题,相反,我在 Github 上的一篇帖子中使用了 @kamal-choudhary 的解决方案,讨论如何将“JWT”添加到每次

axios
调用时都使用
next-auth

使用 @jaketoolson 在 Github 帖子中的帮助,他能够将令牌附加到每个

"Axios"
调用。

解决方案基本上是创建一个

Axios
实例并添加一个拦截器,就像我上面所做的那样,但不仅仅是针对
response
,还针对
request

您将为每个请求添加一个拦截器并检查是否有会话,然后将 JWT 附加到

Authorization header

这成功解决了我的问题,现在

next-auth
react 18
配合得很好。

这是他正在使用的代码...

import axios from 'axios';
import { getSession } from 'next-auth/react';

const baseURL = process.env.SOME_API_URL || 'http://localhost:1337';

const ApiClient = () => {
  const defaultOptions = {
    baseURL,
  };

  const instance = axios.create(defaultOptions);

  instance.interceptors.request.use(async (request) => {
    const session = await getSession();
    if (session) {
      request.headers.Authorization = `Bearer ${session.jwt}`;
    }
    return request;
  });

  instance.interceptors.response.use(
    (response) => {
      return response;
    },
    (error) => {
      console.log(`error`, error);
    },
  );

  return instance;
};

export default ApiClient();

如果对您有用,请不要忘记为他们的帮助点赞......

https://github.com/nextauthjs/next-auth/discussions/3550#discussioncomment-1993281

https://github.com/nextauthjs/next-auth/discussions/3550#discussioncomment-1898233

© www.soinside.com 2019 - 2024. All rights reserved.