这很奇怪,但情况是这样的。
我使用 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”,一切又恢复正常了。
非常感谢任何帮助。
对于那些可能遇到同样问题的人。
我设法通过不包含将令牌添加到 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