繁体   English   中英

使用 React 上下文的 AWS Amplify 保护路由

[英]Protected Routes with AWS Amplify using React context

我正在将一个应用程序从 Firebase 迁移到 AWS Amplify。 我想创建一个 React 上下文,如果用户未登录,它将提供路由保护。

例如我的 Auth.js 文件:

import React, { useEffect, useState, createContext } from 'react'
import fire from './firebase'

export const AuthContext = createContext()

export const AuthProvider = ({ children }) => {
    const [currentUser, setCurrentUser] = useState(null)

    useEffect(() => {
        fire.auth().onAuthStateChanged(setCurrentUser)
    }, [])

    return (
        <AuthContext.Provider value={{ currentUser }}>
            {children}
        </AuthContext.Provider>
    )
}

还有我的 App.js 文件:

import * as React from 'react'
import { BrowserRouter, Switch, Route } from 'react-router-dom'

import Navbar from './components/navbar/navbar'
import Home from './routes/Home'
import Register from './routes/Register'

import Footer from './components/footer/Footer'

import AlertProvider from './components/notification/NotificationProvider'
import MyAlert from './components/notification/Notification'

import { AuthProvider } from './Auth'
import PrivateRoute from './PrivateRoute'

const App = () => {
    return (
        <AuthProvider>
            <BrowserRouter>
                <AlertProvider>
                    <div className="app">
                        <Navbar />
                        <MyAlert />
                        <Switch>
                            <Route path="/" exact component={Home} />
                            <Route
                                path="/register"
                                exact
                                component={Register}
                            />
                            <Route
                                path="/forgot-password"
                                render={(props) => <div>Forgot Password</div>}
                            />
                            <Route path="*" exact={true} component={Home} />
                        </Switch>
                        <Footer />
                    </div>
                </AlertProvider>
            </BrowserRouter>
        </AuthProvider>
    )
}

export default App

这一切都很好。

我如何使用 AWS Amplify 执行类似的操作? 本质上,我将如何创建一个 Auth.js 文件来环绕我的路由并为它们提供用户上下文(当用户的身份验证状态更改时,该文件将更新)。

谢谢!

您可以通过设置一个自定义的protectedRoute HOC 来实现这一点,该 HOC 将用于保护任何需要身份验证的路由。 它将检查用户是否已登录,如果用户未登录,则会将他们重定向到指定的路线。

protectedRoute.js

import React, { useEffect } from 'react'
import { Auth } from 'aws-amplify'

const protectedRoute = (Comp, route = '/profile') => (props) => {
  async function checkAuthState() {
    try {
      await Auth.currentAuthenticatedUser()
    } catch (err) {
      props.history.push(route)
    }
  }
  useEffect(() => {
    checkAuthState()
  })
  return <Comp {...props} />
}

export default protectedRoute

您可以指定默认路由或其他路由,如下所示:

// default redirect route
export default protectedRoute(Profile)

// custom redirect route
export default protectedRoute(Profile, '/sign-in')

您还可以使用来自 aws-amplify 的预构建 HOC,称为withAuthenticator ,它提供 UI 以及检查用户身份验证状态。

配置文件页面的示例用例:

import React, { useState, useEffect } from 'react'
import { Button } from 'antd'
import { Auth } from 'aws-amplify'
import { withAuthenticator } from 'aws-amplify-react'
import Container from './Container'

function Profile() {
  useEffect(() => {
    checkUser()
  }, [])
  const [user, setUser] = useState({}) 
  async function checkUser() {
    try {
      const data = await Auth.currentUserPoolUser()
      const userInfo = { username: data.username, ...data.attributes, }
      setUser(userInfo)
    } catch (err) { console.log('error: ', err) }
  }
  function signOut() {
    Auth.signOut()
      .catch(err => console.log('error signing out: ', err))
  }
  return (
    <Container>
      <h1>Profile</h1>
      <h2>Username: {user.username}</h2>
      <h3>Email: {user.email}</h3>
      <h4>Phone: {user.phone_number}</h4>
      <Button onClick={signOut}>Sign Out</Button>
    </Container>
  );
}

export default withAuthenticator(Profile)

两者的路由是相同的,下面我链接了一个我用于两者的示例。:

import React, { useState, useEffect } from 'react'
import { HashRouter, Switch, Route } from 'react-router-dom'

import Nav from './Nav'
import Public from './Public'
import Profile from './Profile'
import Protected from './Protected'

const Router = () => {
  const [current, setCurrent] = useState('home')
  useEffect(() => {
    setRoute()
    window.addEventListener('hashchange', setRoute)
    return () =>  window.removeEventListener('hashchange', setRoute)
  }, [])
  function setRoute() {
    const location = window.location.href.split('/')
    const pathname = location[location.length-1]
    setCurrent(pathname ? pathname : 'home')
  }
  return (
    <HashRouter>
      <Nav current={current} />
      <Switch>
        <Route exact path="/" component={Public}/>
        <Route exact path="/protected" component={Protected} />
        <Route exact path="/profile" component={Profile}/>
        <Route component={Public}/>
      </Switch>
    </HashRouter>
  )
}

export default Router

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM