react-router-dom v6+OIDC:signInRedirectCallback持续调用无法跳转首页
OIDC回调循环问题排查与解决
问题描述
OIDC初始化完成,signInRedirectCallback执行成功且sessionStorage已正确设置,但该方法出现持续调用的情况(见控制台截图)。页面始终显示Callback组件的“Callback Loading...”,设置完sessionStorage后无法返回首页。
控制台截图:
错误原因分析
- Callback组件未处理路由跳转:调用
signInRedirectCallback后未触发路由跳转,页面一直停留在/signin-oidc路由,组件反复渲染导致方法重复调用。 - signInRedirectCallback逻辑错误:调用
userManager.signinRedirectCallback()后未重新获取用户信息,直接使用空值user更新状态;且异步状态更新后,sessionStorage存入的是旧的isAuthenticated值。 - AuthProvider的useEffect依赖问题:依赖了
isAuthenticated和user,状态变化时重复执行loadUserFromStorage,引发不必要的重渲染循环。 - PrivateRoute的props接收错误:未正确解构props,导致
children无法正常获取。
修复方案
1. 修正Callback组件,添加路由跳转
修改Callback.js,回调完成后跳转到首页或之前存储的页面:
import * as React from 'react'; import { AuthConsumer } from "./AuthProvider"; import { useNavigate } from 'react-router-dom'; export const Callback = () => { const navigate = useNavigate(); return ( <AuthConsumer> {({ signInRedirectCallback }) => { (async () => { await signInRedirectCallback(); // 跳转到存储的页面,默认首页 const redirectUri = sessionStorage.getItem('redirectUri') || '/'; sessionStorage.removeItem('redirectUri'); navigate(redirectUri); })(); return <span>Callback loading</span>; }} </AuthConsumer> ); };
2. 修复signInRedirectCallback逻辑
修改AuthProvider.js中的方法,确保正确获取用户信息并更新状态:
const signInRedirectCallback = async () => { console.log('signInRedirectCallback flow!'); let user = await userManager.getUser(); if(!user) { // 调用回调后重新获取用户 user = await userManager.signinRedirectCallback() .then((newUser) => { console.log('signInRedirectCallback Successful!'); return newUser; }) .catch((error) => { console.error('signInRedirectCallback Error : ', error); throw error; }); const isAuth = !!user; setIsAuthenticated(isAuth); setUser(user); sessionStorage.setItem('access_token', user.access_token); sessionStorage.setItem('id_token', user.id_token); sessionStorage.setItem('isAuthenticated', String(isAuth)); } };
3. 调整AuthProvider的useEffect依赖
移除不必要的依赖,避免重渲染循环:
useEffect(() => { const loadUserFromStorage = async () => { let user = await userManager.getUser(); if (user) { console.log("User flow") const isAuth = !!user; setIsAuthenticated(isAuth); setUser(user); sessionStorage.setItem('access_token', user.access_token); sessionStorage.setItem('id_token', user.id_token); sessionStorage.setItem('isAuthenticated', String(isAuth)); } }; loadUserFromStorage(); }, []); // 仅在组件挂载时执行一次
4. 修正PrivateRoute的props接收
修改PrivateRoute.js的参数结构:
import * as React from 'react'; import { AuthConsumer } from "./AuthProvider"; export const PrivateRoute = ({ children }) => ( <AuthConsumer> {({ isAuthenticated, signInRedirect }) => { console.log(isAuthenticated) console.log(sessionStorage.isAuthenticated) if(isAuthenticated) { return children } else if(sessionStorage.getItem('isAuthenticated') === 'true') { return children } else { signInRedirect(); return <span>PrivateRoute loading</span>; } }} </AuthConsumer> );
5. 修正App.js中的路由语法错误
移除多余的闭合括号:
<Route exact path="/" element={<PrivateRoute><HomePage/></PrivateRoute>} /> <Route exact path="/profile" element={<PrivateRoute><Profile/></PrivateRoute>} />
关键说明
- 回调完成后必须手动触发路由跳转,否则会持续停留在回调页面导致循环调用。
- 异步操作中要确保获取最新用户信息后再更新状态和sessionStorage。
- useEffect依赖需谨慎设置,避免不必要的重渲染循环。
内容的提问来源于stack exchange,提问作者Prakash Raj
相关产品推荐
相关产品推荐

