我的主要 App
组件跟踪当前通过 firebase onAuthStateChanged
回调登录的用户,然后我可以使用它来将用户重定向到 /login
路由,如果用户对象为空。这工作正常,但是如果您在登录页面上导航到不同的路由,您不会被重定向回来,这会导致错误,因为其他路由要求您登录才能正常运行。代码如下:
export function App() {
const auth = firebase.auth();
const [user, setUser] = useState(null);
useEffect(()=>{
auth.onAuthStateChanged(()=> {
setUser(auth.currentUser);
})
}, []);
return (
<BrowserRouter>
<Switch>
<Route path="/login" exact component={LoginPage}/>
<Route path="/" exact component={HomePage}/>
{!user ? <Redirect to="/login"/> : null}
</Switch>
</BrowserRouter>
);
}
我已尝试将 !user ? <Redirect to="/login"/>
移至 Switch
组件的顶部,但这只会使您每次刷新页面时都退出。关于如何解决这个问题的任何想法?谢谢。
答案 0 :(得分:2)
为什么不重构您的 Route 元素以拥有私有路由器和公共路由?私有路由将是那些需要身份验证的路由,而公共路由则不需要它。当有人试图在未经身份验证的情况下访问私有路由时,他们将被自动送走。
创建一个名为 PrivateRoute
的元素并将您的 Firebase 身份验证放入其中。示例:
const PrivateRoute = ({children, ...props}) => {
const auth = firebase.auth();
const [user, setUser] = useState(null);
useEffect(()=>{
auth.onAuthStateChanged(()=> {
setUser(auth.currentUser);
})
}, []);
return (
<Route {...props} render={() => {
return valid === null ?
<div>Some kind of loader/spinner here...</div>
:
user ?
children
:
<Redirect to='/login' />
}} />
)
}
然后在您的 App
中,像这样使用它:
return (
<BrowserRouter>
<Switch>
<PrivateRoute exact path="/">
<HomePage />
</PrivateRoute>
<Route exact path="/login" component={LoginPage} />
</Switch>
</BrowserRouter>
);
如果未通过身份验证,这会将尝试访问 /
的任何人重定向到 /login
。
稍后您创建的任何路由如果需要身份验证,都可以像这样包装。
答案 1 :(得分:0)
我正在使用以下方法并且效果很好(只需复制我现有的有效项目):
import React, {useState, useEffect} from 'react'
import {BrowserRouter as Router, Switch, Route, Redirect} from "react-router-dom"
import {connect} from "react-redux"
import useAuth from './hooks/useAuth'
import styles from './styles.js'
import Landing from './components/Landing'
import Login from './components/Login'
import Logout from './components/Logout'
import Post from './components/Post'
import Users from './components/Users'
import User from './components/User'
import Signup from './components/Signup'
import Profile from './components/Profile'
import AddSocieta from './components/AddSocieta'
import Constructor from './components/Constructor'
const mapStateToProps = state => ({
...state
});
function ConnectedApp() {
const [dimension, setDimention] = useState({windowWidth: 0, windowHeight: 0})
const currentStyles = {
...styles,
showFooterMenuText: styles.showFooterMenuText(dimension),
showSidebar: styles.showSidebar(dimension),
topMenuCollapsed: styles.topMenuCollapsed(dimension),
topMenuHeight: styles.topMenuHeight(dimension),
paddingLeftRight: styles.paddingLeftRight(dimension),
fullScreenMenuFontSize: styles.fullScreenMenuFontSize(dimension),
showSubLogoText: styles.showSubLogoText(dimension),
roundedImageSize: styles.roundedImageSize(dimension)
};
const [auth, profile] = useAuth()
const [isLoggedIn, setIsLoggedIn] = useState(false)
useEffect(() => {
if (auth && auth.uid) {
setIsLoggedIn(true)
} else {
setIsLoggedIn(false)
}
updateDimensions();
window.addEventListener("resize", updateDimensions);
return function cleanup() {
window.removeEventListener("resize", updateDimensions);
}
}, [auth, profile]);
function updateDimensions() {
let windowWidth = typeof window !== "undefined"
? window.innerWidth
: 0;
let windowHeight = typeof window !== "undefined"
? window.innerHeight
: 0;
setDimention({windowWidth, windowHeight});
}
return (<Router>
<Redirect to="/app/gare"/>
<div className="App">
<Switch>
<Route path="/constructor"><Constructor styles={currentStyles}/></Route>
<Route path="/post"><Post/></Route>
<Route path="/login"><Login styles={currentStyles}/></Route>
<Route path="/logout"><Logout styles={currentStyles}/></Route>
<Route path="/users"><Users styles={currentStyles}/></Route>
<Route path="/user/:uid"><User styles={currentStyles}/></Route>
<Route path="/app"><Landing styles={currentStyles}/></Route>
<Route path="/signup" render={isLoggedIn
? () => <Redirect to="/app/gare"/>
: () => <Signup styles={currentStyles}/>}/>
<Route path="/profile" render={isLoggedIn
? () => <Profile styles={currentStyles}/>
: () => <Redirect to="/login"/>}/>
<Route path="/add-societa"><AddSocieta styles={currentStyles}/></Route>
</Switch>
</div>
</Router>);
}
const App = connect(mapStateToProps)(ConnectedApp)
export default App;