![](/img/trans.png)
[英]Firebase - how to restrict authenticated user's access to certain paths?
[英]Using if statement to determine if a Firebase User can access certain React Router paths
我有一個通過 React Router 定義路由的 React Web 應用程序。
應用程序的身份驗證是通過 Firebase 完成的,我想根據用戶是否登錄來保護某些路由。
為了確定用戶是否登錄,我使用了以下函數:
let user = firebase.auth().currentUser;
if (user) {
} else {
}
}
從那里,我想我可以將“受保護”路由放入初始 if 中,因為這將確定用戶是否已登錄,如下所示:
let user = firebase.auth().currentUser;
if (user) {
<div>
<Route path="/dashboard" component={Dashboard} exact />
</div>
} else {
<Route path="/sign-in" component={SignIn} />
}
}
如果用戶未登錄,則他們將被重定向到登錄組件。
然而,這不起作用。 儀表板頁面只是作為空白屏幕返回,而不是重定向。
確實,控制台中顯示了一條錯誤消息:
警告:失敗的道具類型:提供給
Switch
道具children
無效,需要一個 ReactNode。
作為參考,這是我的完整組件:
class App extends Component {
constructor(props) {
super(props)
this.userLoggedIn = this.userLoggedIn.bind(this)
}
userLoggedIn = () => {
let user = firebase.auth().currentUser;
if (user) {
<div>
<Route path="/dashboard" component={Dashboard} exact />
</div>
} else {
<Route path="/sign-in" component={SignIn} />
}
}
render() {
return (
<div>
<Switch>
{this.userLoggedIn}
<Route exact path="/" component={Homepage} />
<Route path="/sign-in" component={SignIn} />
<Route path="/register" component={Register} />
</Switch>
</div>
)
}
}
我知道邏輯有缺陷,但是有沒有辦法重構我的代碼來實現這個非常簡單的 hack 以使用 Firebase Auth 獲取受保護的路由?
希望這很清楚,如果需要更多信息,請告訴我。
編輯:根據答案編輯了我的代碼,但現在收到以下錯誤消息:
TypeError: Right side of assignment cannot be destructured
PrivateRoute
src/PrivateRoute.js:8
5 | import { AuthContext } from './Auth'
6 |
7 | export default function PrivateRoute({ component: RouteComponent, ...rest }) {
> 8 | const {currentUser} = useContext(AuthContext)
9 | return (
10 | <Route
11 | {...rest}
我更新的代碼...
身份驗證.js
import React, { useEffect, useState } from 'react'
import * as firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
import firebaseConfig from './firebaseConfig';
export const AuthContext = React.createContext();
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState(null);
useEffect(() => {
firebase.auth().onAuthStateChanged(setCurrentUser);
}, []);
return (
<AuthContext.Provider
value={{currentUser}}
>
{children}
</AuthContext.Provider>
)
}
私有路由.js
import React, { useContext } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AuthContext } from './Auth'
export default function PrivateRoute({ component: RouteComponent, ...rest }) {
const { currentUser } = useContext(AuthContext)
return (
<Route
{...rest}
render={routeProps =>
!!currentUser ? (
<RouteComponent {...routeProps} currentUser={currentUser} />
) : (
<Redirect to={'/signin'}/>
)
}
/>
)
}
應用程序.js
import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import PrivateRoute from './PrivateRoute';
import './App.css';
import * as firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
import firebaseConfig from './firebaseConfig';
class App extends Component {
render() {
return (
<div>
<Switch>
<PrivateRoute path="/dashboard" component={Dashboard} />
<Route exact path="/" component={Homepage} />
<Route path="/sign-in" component={SignIn} />
<Route path="/register" component={Register} />
</Switch>
</div>
)
}
}
export default App;
有兩種方法可以解決這個問題並稍微清理一下。
假設您只希望經過身份驗證的用戶訪問儀表板頁面
簡單的選擇:
class App extends Component {
state = {
currentUser: undefined
}
componentDidMount(){
const user = firebase.auth().currentUser
this.setState({currentUser: user})
}
render() {
return (
<div>
<Switch>
<Route exact path="/dashboard">
{this.state.user ? (
<Dashboard />
) : (
<Redirect to={"/login"} />
)}
</Route>
</Switch>
</div>
)
}
}
一些注意事項:
componentDidMount()
掛載時,最好獲取當前用戶並設置任何初始狀態。<Redirect to={path}/>
組件,它非常適合諸如檢查經過身份驗證的用戶之類的用例。清潔工(也是我的首選):
如果您想抽象身份驗證過程並從長遠來看讓您的生活更簡單,您可以創建 2 個文件(例如base.js
、 Auth.js
和PrivateRoute.js
)
base.js
是我們要初始化 firebase 的地方
import * as firebase from 'firebase/app' const app = firebase.initializeApp({ apiKey: process.env.REACT_APP_FIREBASE_KEY, authDomain: process.env.REACT_APP_FIREBASE_DOMAIN, databaseURL: process.env.REACT_APP_FIREBASE_DATABASE, projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID, storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID, measurementId: process.env.REACT_APP_MEASUREMENT_ID }); export default app;
筆記:
我已將process.env......
作為 API 密鑰的值,因為將密鑰保存在.env
文件中始終是最佳實踐。
Auth.js
是我們將在身份驗證狀態更改時處理獲取身份驗證用戶的地方
身份驗證.js:
import React, { useEffect, useState } from 'react'
import app from './base'
export const AuthContext = React.createContext();
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState(null);
useEffect(() => {
app.auth().onAuthStateChanged(setCurrentUser);
}, []);
return (
<AuthContext.Provider
value={{currentUser}}
>
{children}
</AuthContext.Provider>
)
}
筆記:
PrivateRoute.js:
import React, { useContext } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AuthContext } from './Auth'
export default function PrivateRoute({ component: RouteComponent, ...rest }) {
const currentUser = useContext(AuthContext)
return (
<Route
{...rest}
render={routeProps =>
!!currentUser ? (
<RouteComponent {...routeProps} currentUser={currentUser} />
) : (
<Redirect to={'/login'}/>
)
}
/>
)
}
筆記:
Auth.js
文件中導入身份驗證上下文並獲取當前用戶。PrivateRoute
,它檢查是否有當前用戶,如果有,使用react-router-dom
包中的Route
和Redirect
我們可以將用戶重定向到/login
頁面,如果他們沒有經過身份驗證,或者重定向到RouteComponent
與其他道具一起傳遞(如果有的話)。RouteComponent
的currentUser
作為 props 傳遞,以便它在該組件中可用。 有了這個,您現在可以像這樣使用PrivateRoute
組件來確保只有經過身份驗證的用戶才能使用給定的組件:
import PrivateRoute from "./PrivateRoute";
import Dashboard from "./Dashboard"
<PrivateRoute exact path="/dashboard" component={Dashboard} />
this.userLoggedIn
是一個函數,因此它必須返回您希望它呈現的 JSX:
userLoggedIn = () => {
let user = firebase.auth().currentUser;
if (user) {
return (<div>
<Route path="/dashboard" component={Dashboard} exact />
</div>);
} else {
return <Route path="/sign-in" component={SignIn} />;
}
}
同樣在您的渲染函數中,您想要調用函數this.userLoggedIn
,而不僅僅是將其作為值放入。 否則它不會做任何事情:
render() {
return (
<div>
<Switch>
{this.userLoggedIn()}
<Route exact path="/" component={Homepage} />
<Route path="/sign-in" component={SignIn} />
<Route path="/register" component={Register} />
</Switch>
</div>
)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.