Heim  >  Fragen und Antworten  >  Hauptteil

Leiten Sie nicht authentifizierte Benutzer um, AWS Amplify

Ich versuche, eine Webanwendung mit AWS Amplify zu erstellen. Ich habe die Authentifizierung konfiguriert, möchte aber, dass bestimmte Seiten nur für authentifizierte Benutzer verfügbar sind. Beispielsweise kann die Startseite von jedem gesehen werden, „/dashboard“ jedoch nur von angemeldeten Benutzern. Ich verwende derzeit AWS Amplify für mein Backend und ein React-Frontend und verwende React-Router v6 für die Weiterleitung zwischen Seiten.

Derzeit ist mein Routing-Code sehr einfach (ich verwende React zum ersten Mal) und befindet sich in 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;

Ich habe zuerst versucht, die Seite, die ich authentifizieren wollte, mit withAuthenticator zu umbrechen, aber das führte nur zu einer Schleife, die das Anmeldefeld anzeigte.

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);

Ich habe auch versucht, eine Funktion hinzuzufügen, um zu prüfen, ob der Benutzer authentifiziert ist, und etwas anderes zurückzugeben, aber diese zeigt nur einen leeren Bildschirm für authentifizierte und nicht authentifizierte Benutzer. Ich denke, das liegt daran, dass es async ist, aber ich kenne mich mit React nicht gut genug aus, um zu verstehen, warum und wie man das Problem beheben kann.

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>
      </>
    )
  }
}

Ich habe auch versucht herauszufinden, ob es eine Möglichkeit gibt, asynchron weiterzuleiten, bin mir aber nicht sicher, wie ich das implementieren soll.

Herausgeber:

Die Lösung von

@Jlove funktioniert bereits wie erwartet, mein aktualisierter App.jsRouting-Code lautet wie folgt:

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;

P粉533898694P粉533898694376 Tage vor687

Antworte allen(2)Ich werde antworten

  • P粉725827686

    P粉7258276862023-09-10 10:13:10

    您将希望将保护路由的逻辑与每个路由渲染的内容分开。不要将身份验证与您要在路由上呈现的UI/内容组件混合在一起。

    一种常见的保护模式是使用布局路由来包装您想要保护访问权限的整个路由组。您将创建一个布局路由组件,触发一个效果来检查当前用户的身份验证状态,并有条件地返回:

    • 没有/加载中(如果状态尚未知
    • 用于受保护内容的Outlet如果用户已经通过身份验证
    • 重定向到非受保护路由(如果用户未经身份验证

    这样可以防止(a)在知道用户未经身份验证之前意外访问受保护的页面,以及(b)在知道用户已经通过身份验证之前意外重定向到登录页面。

    示例:

    const checkAuthentication = async () => {
      try {
        await Auth.currentAuthenticatedUser();
        return true;
      } catch {
        return false;
      }
    };
    
    import { Outlet, Navigate } from 'react-router-dom';
    
    const ProtectedRoute = () => {
      const [isAuth, setIsAuth] = useState(undefined);
    
      useEffect(() => {
        checkAuthentication()
          .then(() => setIsAuth(true))
          .catch(() => setIsAuth(false));
      }, []);
    
      if (isAuth === undefined) {
        return null; // 或加载中的旋转器/指示器等
      }
        
      return isAuth ? <Outlet /> : <Navigate to="/login" replace />;
    }

    包装需要受保护的路由。

    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';
    import ProtectedRoute from './components/ProtectedRoute';
    
    const App = () => {
      return (
        <BrowserRouter>
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/login" element={<Login />} />
            <Route element={<ProtectedRoute />}>
              <Route path="/dashboard" element={<Dashboard />} />
              {/* ... 其他受保护的路由 ... */}
            </Route>
            <Route path="*" element={<ErrorPage />} />
          </Routes>
        </BrowserRouter>
      );
    }
    
    export default App;

    Antwort
    0
  • P粉978551081

    P粉9785510812023-09-10 09:28:28

    以下是一种方法,通过将组件路由包装在授权组件中来实现:

    <Route 
        path="/somePathToProtect"
        element={
            <RequireAuth>
                <Dashboard />
            </RequireAuth>
        }
    />
    
    export function RequireAuth({children}) {
        const navigate = useNavigate();
    
        const [isAuth, setIsAuth] = useState(null);
    
        useEffect(() => {
            Auth.currentAuthenticatedUser()
                .then(
                    () => setIsAuth(true)
                )
                .catch(() => {
                    navigate('/routeToCatchNonAuth')
                })
        }, [])
    
        return isAuth && children;
    }

    这里的目标是基于Auth返回的结果来保护您的路由。如果Auth选择了catch路由,利用路由器将用户导航到未经授权的页面。

    Antwort
    0
  • StornierenAntwort