簡體   English   中英

使用 if 語句確定 Firebase 用戶是否可以訪問某些 React Router 路徑

[英]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()掛載時,最好獲取當前用戶並設置任何初始狀態。
  • React 不使用構造函數,只支持像我一樣簡單地聲明初始狀態
  • 最后,react-router 有一個<Redirect to={path}/>組件,它非常適合諸如檢查經過身份驗證的用戶之類的用例。

清潔工(也是我的首選):

如果您想抽象身份驗證過程並從長遠來看讓您的生活更簡單,您可以創建 2 個文件(例如base.jsAuth.jsPrivateRoute.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>
    )
}

筆記:

  • 不要忘記導入 React、useState、useEffect 和 firebase
  • 此文件將提供身份驗證上下文,以便您可以從 React 應用程序的任何位置獲取它

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包中的RouteRedirect我們可以將用戶重定向到/login頁面,如果他們沒有經過身份驗證,或者重定向到RouteComponent與其他道具一起傳遞(如果有的話)。
  • 我們還將RouteComponentcurrentUser作為 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM