NextAuth令牌轮换失效问题排查与替代方案咨询
NextAuth令牌轮换失效问题及自定义方案咨询
我们团队基于Next.js开发对接自研外部API的Web应用,采用NextAuth实现身份认证,目前遇到令牌轮换失效的问题:
- 登录成功后,从后端获取有效期10分钟的Access Token和有效期更长的Refresh Token,将Access Token存入NextAuth会话,通过Axios发起API请求时携带该令牌。
- 当Access Token过期时,通过Axios拦截器调用刷新接口获取新的Access Token和Refresh Token,接口调用成功,但NextAuth仍携带旧的过期令牌发起请求,导致请求失败。
这是我首次使用Next.js,团队目前考虑放弃NextAuth,改用自定义方案:将Refresh Token存入Redis并通过HttpOnly Cookie传递,SessionId存入本地存储实现持久登录,Access Token存入内存并在请求时携带,但不确定该方案是否可靠,希望得到协助。
相关代码
NextAuth配置代码
const authOptions: NextAuthOptions = { session: { strategy: "jwt", }, providers:[ CredentialsProvider({ type: "credentials", credentials: {}, async authorize(credentials, req){ const { username, password } = credentials as { username: string; password: string; }; if(!credentials){ return null } const userData = { username: username, password: password } try { const response = await axios.post(`${BASE_URL}/login`, userData); if(response?.data){ const user: jwtDecodedAttributes = jwt_decode(response?.data?.userToken); return { id: user.userId, name: user.username, role: user.role, profilepicture: user.profilepicture, iat: user?.iat, exp: user?.exp, username: user?.username, token: response?.data?.userToken, email: user.email, userId: user?.userId, refresh: response?.data.userRefreshToken }; } } catch (error) { } return null } }) ], pages: { signIn: "/login", }, callbacks:{ async jwt({token, user, trigger, session}){ if (trigger === "update") { return { ...token, ...session.user }; } return {...token, ...user} ; }, async session({session, token, user}){ session.user = token return session } } }; export default NextAuth(authOptions);
刷新令牌函数
export const RefreshFunction = ()=>{ const { status, data, update } = useSession(); const refreshToken = async()=>{ const getItem = localStorage.getItem('refresh'); const refreshData = { refresh: getItem, } if(data?.user.refresh){ try { const res = await axios.post<axiosGetRefreshTokenAttributes>(`${BASE_URL}/refresh`, refreshData); const accessToken = res?.data?.userToken const refreshToken = res?.data?.refreshToken localStorage.removeItem('refresh'); if(data?.user){ await update({ ...data, user:{ ...data?.user, token: accessToken, refresh: refreshToken } }) } localStorage.setItem('refresh', refreshToken as string) } catch (error) { return error } } } return refreshToken };
Axios拦截器函数
const useAxiosPrivate = () =>{ const { status, data } = useSession(); const refreshToken = RefreshFunction() useEffect(() =>{ const requestInterceptors = axiosPrivate.interceptors.request.use( config =>{ if(!config.headers['authorization']){ config.headers['authorization'] = `Bearer ${data?.user?.token}` } return config; }, (error) => Promise.reject(error) ); const responseIntercept = axiosPrivate.interceptors.response.use( response => response, async (error)=>{ const prevRequest = error?.config; console.log(error.response.status, 'kkk') if(error?.response.status === 401 && !prevRequest?.sent){ prevRequest.sent = true; const token = await refreshToken() prevRequest.headers['authorization'] = `Bearer ${token}`; return axiosPrivate(prevRequest); } return Promise.reject(error); } ); return()=>{ axiosPrivate.interceptors.request.eject(requestInterceptors) axiosPrivate.interceptors.response.eject(responseIntercept) } }, [data?.user?.token]) return axiosPrivate; }; export default useAxiosPrivate;
API调用示例
const { status, data } = useSession(); await axiosPrivate.post(`/createcompany`, companyData, {withCredentials: true, headers: {Authorization: ` ${data?.user.token}`}});
补充说明:如前所述,刷新接口会在令牌过期时被调用并生成新令牌,但新令牌无法更新到NextAuth会话,报错显示Access Token已过期。
内容的提问来源于stack exchange,提问作者princekings
相关产品推荐
相关产品推荐

