React SPA集成AzureAD/MSAL:登录后跳转Home页异常重定向问题
问题描述
开发React单页应用(SPA)时,使用AzureAD/MSAL实现认证功能:
- Landing页路径为
/,包含登录按钮 - Home页路径为
/home - 需求:未认证用户直接访问
/home时自动重定向到Landing页
当前实现的重定向逻辑如下:
const navigate = useNavigate(); const { instance, inProgress } = useMsal(); const isAuthenticated = useIsAuthenticated(); useEffect(() => { if (inProgress === InteractionStatus.None && !isAuthenticated) { navigate('/'); } }, [inProgress, isAuthenticated, navigate]);
直接访问/home时逻辑正常,但用户首次在Landing页完成登录后,页面跳转到/home时上述重定向逻辑会触发,将用户带回Landing页,需再次点击登录才能进入/home。
完整代码:
import React, { useEffect } from 'react'; import { BrowserRouter as Router, Routes, Route, Link, useNavigate } from 'react-router-dom'; import { MsalProvider, useMsal, useIsAuthenticated } from '@azure/msal-react'; import { InteractionStatus } from '@azure/msal-browser'; import ReactDOM from 'react-dom/client'; import { PublicClientApplication } from '@azure/msal-browser'; import { msalConfig } from './js/authConfig'; const LandingPage = () => { const { instance } = useMsal(); const handleLogin = () => { instance.loginRedirect(); }; return ( <div> <h1>Landing Page</h1> <button onClick={handleLogin}>Login</button> </div> ); }; const HomePage = () => { const navigate = useNavigate(); const { instance, inProgress } = useMsal(); const isAuthenticated = useIsAuthenticated(); useEffect(() => { if (inProgress === InteractionStatus.None && !isAuthenticated) { navigate('/'); } }, [inProgress, isAuthenticated, navigate]); return ( <div> <h1>Home Page</h1> </div> ); }; const msalInstance = new PublicClientApplication(msalConfig); ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <MsalProvider instance={msalInstance}> <Router> <Routes> <Route path="/" element={<LandingPage />} /> <Route path="/home" element={<HomePage />} /> </Routes> </Router> </MsalProvider> </React.StrictMode> );
msalConfig相关配置:
redirectUri: "/home", navigateToLoginRequestUrl: false,
原因分析
首次登录重定向到/home时,MSAL的认证状态尚未完成更新:
- 登录重定向返回后,MSAL需要时间处理令牌、同步内部状态
- 此时
useIsAuthenticated()返回false,且inProgress已变为InteractionStatus.None,触发了重定向逻辑
解决方案
方案1:初始化时等待重定向流程完成
在应用入口处先处理MSAL的重定向Promise,确保认证状态更新后再渲染组件:
const msalInstance = new PublicClientApplication(msalConfig); // 等待重定向认证流程结束后再渲染组件 msalInstance.handleRedirectPromise().then(() => { ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <MsalProvider instance={msalInstance}> <Router> <Routes> <Route path="/" element={<LandingPage />} /> <Route path="/home" element={<HomePage />} /> </Routes> </Router> </MsalProvider> </React.StrictMode> ); });
方案2:优化Home页的状态判断
修改Home页的逻辑,增加加载状态判断,避免在认证流程未完成时触发重定向:
const HomePage = () => { const navigate = useNavigate(); const { instance, inProgress } = useMsal(); const isAuthenticated = useIsAuthenticated(); useEffect(() => { if (inProgress === InteractionStatus.None && !isAuthenticated) { navigate('/'); } }, [inProgress, isAuthenticated, navigate]); // 认证流程进行中时显示加载状态,避免页面闪烁 if (inProgress !== InteractionStatus.None) { return <div>加载中...</div>; } return ( <div> <h1>Home Page</h1> </div> ); };
方案3:使用路由守卫组件(推荐)
自定义路由守卫统一处理权限控制,代码更模块化:
// 自定义受保护路由组件 const ProtectedRoute = ({ children }) => { const isAuthenticated = useIsAuthenticated(); const { inProgress } = useMsal(); const navigate = useNavigate(); useEffect(() => { if (inProgress === InteractionStatus.None && !isAuthenticated) { navigate('/'); } }, [inProgress, isAuthenticated, navigate]); if (inProgress !== InteractionStatus.None || !isAuthenticated) { return <div>加载中...</div>; } return children; }; // 修改路由配置 <Routes> <Route path="/" element={<LandingPage />} /> <Route path="/home" element={ <ProtectedRoute> <HomePage /> </ProtectedRoute> } /> </Routes>
内容的提问来源于stack exchange,提问作者RaGe
相关产品推荐
相关产品推荐

