React+AWS Amplify实现未认证用户页面访问重定向
AWS Amplify + React Router v6 路由权限控制实现方案
需求背景
使用AWS Amplify作为后端、React作为前端,搭配react-router v6开发Web应用,已配置认证功能,需实现:
- 首页(/)对所有用户开放
- 仅认证用户可访问/dashboard页面
当前基础路由代码(App.js)
import React from 'react'; import { BrowserRouter, Route, Routes, } from 'react-router-dom'; import Login from './pages/Login'; import Home from './pages/Home'; import Dashboard from './pages/Dashboard'; import ErrorPage from './pages/ErrorPage'; const App = () => { return ( <BrowserRouter> <Routes> <Route exact path="/" element={<Home />} /> <Route path="/login" element={<Login />} /> <Route path="/dashboard" element={<Dashboard />} /> <Route path="*" element={<ErrorPage />} /> </Routes> </BrowserRouter> ); } export default App;
尝试的方案及问题
方案1:使用withAuthenticator包裹页面
给Dashboard组件添加withAuthenticator包装,出现登录弹窗循环问题:
function Dashboard({ signOut, user }) { return ( <> <h1>Hello {user.username}, this is still in development.</h1> <button onClick={signOut}> Sign out</button> </> ); } export default withAuthenticator(Dashboard);
方案2:异步函数判断认证状态
编写异步函数判断用户是否认证,根据结果返回不同内容,但无论用户是否认证,页面都显示空白,推测是异步逻辑导致的渲染问题:
async function isAuthed() { try { await Auth.currentAuthenticatedUser(); return true; } catch(e) { return false; } } async function Dashboard() { if (await isAuthed()) { return ( <> <h1>Hello, this is still in development.</h1> </> ); } else { return ( <> <h1>Please login to view this page.</h1> </> ) } }
生效的解决方案
通过编写RequireAuth高阶组件实现路由守卫,更新后的App.js代码如下:
import React, { useState, useEffect } from 'react'; import { BrowserRouter, Route, Routes, useNavigate, } from 'react-router-dom'; import { Amplify, Auth } from 'aws-amplify' import Login from './pages/Login'; import Home from './pages/Home'; import Dashboard from './pages/Dashboard'; import ErrorPage from './pages/ErrorPage'; import Unauthenticated from './pages/Unauthenticated'; function RequireAuth({ children }) { const navigate = useNavigate(); const [isAuth, setIsAuth] = useState(null); useEffect(() => { Auth.currentAuthenticatedUser() .then(() => setIsAuth(true)) .catch(() => { navigate("/unauthenticated") }) }, []) return isAuth && children; } const App = () => { return ( <BrowserRouter> <Routes> <Route exact path="/" element={<Home />} /> <Route path="/login" element={<Login />} /> <Route path="/dashboard" element={ <RequireAuth> <Dashboard /> </RequireAuth> } /> <Route path="*" element={<ErrorPage />} /> <Route path="/unauthenticated" element={<Unauthenticated />} /> </Routes> </BrowserRouter> ); } export default App;
内容的提问来源于stack exchange,提问作者supinie
相关产品推荐
相关产品推荐

