
本文介绍如何在 aws amplify + react router v6 项目中,为特定路由(如 `/dashboard`)添加认证保护,确保仅已登录用户可访问,未认证用户自动跳转至登录页或提示页。
在基于 AWS Amplify 构建的 react 应用中,实现页面级访问控制是常见需求。单纯使用 withAuthenticator 包裹组件会导致重复渲染登录框、路由循环等问题;而直接在函数组件内异步调用 Auth.currentAuthenticatedUser() 又会因 React 渲染机制(无法在渲染函数中 await)导致白屏或逻辑失效。正确方案是采用路由守卫(Route Guard)模式——通过自定义高阶组件拦截路由访问,在导航前完成身份校验。
以下是推荐的生产就绪实现方式:
✅ 正确做法:创建 RequireAuth 路由守卫组件
// src/components/RequireAuth.jsx import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Auth } from 'aws-amplify'; export function RequireAuth({ children }) { const navigate = useNavigate(); const [isAuth, setIsAuth] = useState(null); // null 表示校验中,避免闪屏 useEffect(() => { const checkAuth = async () => { try { await Auth.currentAuthenticatedUser(); // 若已登录,返回 CognitoUser 对象 setIsAuth(true); } catch (error) { console.warn('User not authenticated:', error); navigate('/login', { replace: true, state: { from: window.location.pathname } // 记录来源页,登录后可跳回 }); } }; checkAuth(); }, [navigate]); // 渲染占位符(如加载 Spinner),提升用户体验 if (isAuth === NULL) { return Checking authentication...; } return isAuth ? children : null; }
✅ 在 app.js 中集成守卫路由
// src/App.js import React from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; import { Amplify } from 'aws-amplify'; import awsExports from './aws-exports'; Amplify.configure(awsExports); import Home from './pages/Home'; import Login from './pages/Login'; import Dashboard from './pages/Dashboard'; import ErrorPage from './pages/ErrorPage'; function App() { return ( } /> } /> {/* 受保护路由:仅认证用户可进入 */} } /> } /> ); } export default App;
⚠️ 关键注意事项
- 不要在 element 中直接传入异步函数或条件渲染逻辑:React Router v6 的 element 属性期望一个同步 JSX 元素,而非返回 JSX 的函数。
- 避免 useEffect 空依赖数组中的裸 Auth.currentAuthenticatedUser():应包裹在 async 函数中并显式 await,否则 .then().catch() 链易丢失错误上下文。
- 添加加载态反馈:isAuth === null 时显示轻量加载提示,防止白屏,提升 ux。
- 保留来源路径:跳转登录页时通过 state.from 记录原始目标路径,登录成功后可重定向回 /dashboard(需在 Login 组件中读取 useLocation().state?.from)。
- 服务端校验不可替代:前端守卫仅用于体验优化,所有敏感 API 调用仍须在 Amplify 后端(如 graphql Resolver 或 REST Lambda)中进行严格权限验证。
✅ 进阶建议:统一认证状态管理
对于中大型应用,推荐结合 Context 或 Zustand 管理全局认证状态,避免每个受保护路由重复调用 Auth.currentAuthenticatedUser()。例如:
// src/contexts/AuthContext.jsx import { createContext, useContext, useEffect, useState } from 'react'; import { Auth } from 'aws-amplify'; const AuthContext = createContext(); export function AuthProvider({ children }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const checkUser = async () => { try { const currentUser = await Auth.currentAuthenticatedUser(); setUser(currentUser); } catch (e) { setUser(null); } finally { setLoading(false); } }; checkUser(); }, []); return ( {!loading && children} ); } export function useAuth() { const context = useContext(AuthContext); if (!context) throw new Error('useAuth must be used within AuthProvider'); return context; }
然后在 RequireAuth 中消费该 Context,实现状态复用与响应式更新。
通过以上方案,你将获得健壮、可维护且符合 React 最佳实践的认证路由控制能力,无缝集成 AWS Amplify 身份服务。