8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

如何使用 react-router-dom 创建受保护的路线?

Harley 1月前

38 0

如何使用 react-router-dom 创建受保护的路由并将响应存储在 localStorage 中,以便用户下次尝试打开时可以再次查看其详细信息。登录后,他们应该

如何创建受保护的路由 react-router-dom 并将响应存储在 localStorage 中,以便用户下次尝试打开时可以再次查看其详细信息。登录后,他们应该重定向到仪表板页面。

所有功能均添加在 ContextApi.代码sandbox 链接中: Code

我尝试过,但没能实现

路线页面

import React, { useContext } from "react";
import { globalC } from "./context";
import { Route, Switch, BrowserRouter } from "react-router-dom";
import About from "./About";
import Dashboard from "./Dashboard";
import Login from "./Login";
import PageNotFound from "./PageNotFound";

function Routes() {
  const { authLogin } = useContext(globalC);
  console.log("authLogin", authLogin);

  return (
    <BrowserRouter>
      <Switch>
        {authLogin ? (
          <>
            <Route path="/dashboard" component={Dashboard} exact />
            <Route exact path="/About" component={About} />
          </>
        ) : (
          <Route path="/" component={Login} exact />
        )}

        <Route component={PageNotFound} />
      </Switch>
    </BrowserRouter>
  );
}
export default Routes;

上下文页面

import React, { Component, createContext } from "react";
import axios from "axios";

export const globalC = createContext();

export class Gprov extends Component {
  state = {
    authLogin: null,
    authLoginerror: null
  };
  componentDidMount() {
    var localData = JSON.parse(localStorage.getItem("loginDetail"));
    if (localData) {
      this.setState({
        authLogin: localData
      });
    }
  }

  loginData = async () => {
    let payload = {
      token: "ctz43XoULrgv_0p1pvq7tA",
      data: {
        name: "nameFirst",
        email: "internetEmail",
        phone: "phoneHome",
        _repeat: 300
      }
    };
    await axios
      .post(`https://app.fakejson.com/q`, payload)
      .then((res) => {
        if (res.status === 200) {
          this.setState({
            authLogin: res.data
          });
          localStorage.setItem("loginDetail", JSON.stringify(res.data));
        }
      })
      .catch((err) =>
        this.setState({
          authLoginerror: err
        })
      );
  };
  render() {
    // console.log(localStorage.getItem("loginDetail"));
    return (
      <globalC.Provider
        value={{
          ...this.state,
          loginData: this.loginData
        }}
      >
        {this.props.children}
      </globalC.Provider>
    );
  }
}
帖子版权声明 1、本帖标题:如何使用 react-router-dom 创建受保护的路线?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Harley在本站《reactjs》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 问题

    <BrowserRouter>
      <Switch>
        {authLogin ? (
          <>
            <Route path="/dashboard" component={Dashboard} exact />
            <Route exact path="/About" component={About} />
          </>
        ) : (
          <Route path="/" component={Login} exact />
        )}
    
        <Route component={PageNotFound} />
      </Switch>
    </BrowserRouter>
    

    除了 Switch Route Redirect 。如果您想像这样“嵌套”,则需要将每个组件包装在通用路由中,但这是完全没有必要的。

    您的登录组件也无法处理重定向回任何最初访问的“主页”或私人路线。

    解决方案

    react-router-dom v6

    在版本 6 中,自定义路由组件已不再受欢迎,首选方法是使用 auth 布局组件。

    import { Navigate, Outlet } from 'react-router-dom';
    
    const PrivateRoutes = () => {
      const location = useLocation();
      const { authLogin } = useContext(globalC);
    
      if (authLogin === undefined) {
        return null; // or loading indicator/spinner/etc
      }
    
      return authLogin 
        ? <Outlet />
        : <Navigate to="/login" replace state={{ from: location }} />;
    }
    

    ...

    <BrowserRouter>
      <Routes>
        <Route path="/" element={<PrivateRoutes />} >
          <Route path="dashboard" element={<Dashboard />} />
          <Route path="about" element={<About />} />
        </Route>
        <Route path="/login" element={<Login />} />
        <Route path="*" element={<PageNotFound />} />
      </Routes>
    </BrowserRouter>
    

    或者

    const routes = [
      {
        path: "/",
        element: <PrivateRoutes />,
        children: [
          {
            path: "dashboard",
            element: <Dashboard />,
          },
          {
            path: "about",
            element: <About />
          },
        ],
      },
      {
        path: "/login",
        element: <Login />,
      },
      {
        path: "*",
        element: <PageNotFound />
      },
    ];
    

    ...

    export default function Login() {
      const location = useLocation();
      const navigate = useNavigate();
      const { authLogin, loginData } = useContext(globalC);
    
      useEffect(() => {
        if (authLogin) {
          const { from } = location.state || { from: { pathname: "/" } };
          navigate(from, { replace: true });
        }
      }, [authLogin, location, navigate]);
    
      return (
        <div
          style={{ height: "100vh" }}
          className="d-flex justify-content-center align-items-center"
        >
          <button type="button" onClick={loginData} className="btn btn-primary">
            Login
          </button>
        </div>
      );
    }
    

    react-router-dom v5

    创建一个 PrivateRoute 使用您的身份验证上下文的组件。

    const PrivateRoute = (props) => {
      const location = useLocation();
      const { authLogin } = useContext(globalC);
    
      if (authLogin === undefined) {
        return null; // or loading indicator/spinner/etc
      }
    
      return authLogin ? (
        <Route {...props} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: location }
          }}
        />
      );
    };
    

    更新您的 Login 组件以处理重定向回正在访问的原始路线。

    export default function Login() {
      const location = useLocation();
      const history = useHistory();
      const { authLogin, loginData } = useContext(globalC);
    
      useEffect(() => {
        if (authLogin) {
          const { from } = location.state || { from: { pathname: "/" } };
          history.replace(from);
        }
      }, [authLogin, history, location]);
    
      return (
        <div
          style={{ height: "100vh" }}
          className="d-flex justify-content-center align-items-center"
        >
          <button type="button" onClick={loginData} className="btn btn-primary">
            Login
          </button>
        </div>
      );
    }
    

    在“平面列表”中呈现所有路线

    function Routes() {
      return (
        <BrowserRouter>
          <Switch>
            <PrivateRoute path="/dashboard" component={Dashboard} />
            <PrivateRoute path="/About" component={About} />
            <Route path="/login" component={Login} />
            <Route component={PageNotFound} />
          </Switch>
        </BrowserRouter>
      );
    }
    
  • 先生您好。我试过您的代码,运行良好。但我遇到了一些问题。对我来说,没有主页,登录页面是默认页面,一旦用户尝试根据响应登录,它将导航到仪表板,侧边栏仅在受保护的路由中可用。Codesandbox 链接:codesandbox.io/s/protuctedroute-d26tz @Drew

  • @learner62 我的沙盒中的 \'home\' 路由仅用于提供起点,而不会尝试启动身份验证流程。不过,我还是要提醒您不要将 \'/\' 路径作为身份验证路径。话虽如此,您的沙盒似乎正在运行,您只需确保不要在登录路径 \'/\' 和重定向回 \'/\' 的 PrivateRoute 之间创建渲染循环。

  • 如果您已登录并在受保护的路由上刷新页面,它将使用上面的代码带您离开页面。这是因为在刷新期间上下文最初为空,然后才从数据库中提取数据。有什么建议可以纠正这个问题吗?

  • @Ufeneiaugustine 添加第三个加载或待处理\'状态\',既不是\'已认证\'也不是\'未认证\',这样您可以呈现 null,或加载旋转器,或任何其他\'处理\'UI,直到确定是否应允许用户继续进入页面或是否应将其弹出。

  • @BeniKeyserman 如果我理解正确的话,您可以使用 \'/\' 路由重定向到已知/已处理的路由,类似于设置默认路由。 PrivateRoutes 布局路由不需要位于 \'/\' 路径上,事实上,如果您不需要布局路由参与路由匹配,那么布局路由可以完全无路径。

  • 对于 v6:

    import { Routes, Route, Navigate } from "react-router-dom";
    
    function App() {
      return (
        <Routes>
          <Route path="/public" element={<PublicPage />} />
          <Route
            path="/protected"
            element={
              <RequireAuth redirectTo="/login">
                <ProtectedPage />
              </RequireAuth>
            }
          />
        </Routes>
      );
    }
    
    function RequireAuth({ children, redirectTo }) {
      let isAuthenticated = getAuth();
      return isAuthenticated ? children : <Navigate to={redirectTo} />;
    }
    

    文档链接: https://gist.github.com/mjackson/d54b40a094277b7afdd6b81f51a0393f

  • 我不知道为什么只有这个代码有效!!以上所有 V6 解决方案均无效。无论如何,谢谢@Yauhen

  • Enc 1月前 0 只看Ta
    引用 10

    这是针对 Reactjs 较新的答案

    React Router Dom:^ v6

    //App.js
    <Route path="/"
           element={<HomePage /> } />
    
    <Route path="/dashboard"
           element={<AuthMiddleware> <DashboardPage /> </AuthMiddleware>}
    />
    
    // AuthMiddelware.js
    import { Navigate } from "react-router-dom"
    
    export const AuthMiddleware = (props) => { 
        
        const token = true; // get login status here
        
        const { auth=token, children, redirect = '/login' } = props; 
    
        if (!auth) {
           return <Navigate to={redirect} replace />;
        }
        return children;
     };
    
  • 如果您想要一种简单的实现方法,那么请使用 App.js 中的登录,如果用户已登录,则设置用户变量。 如果设置了用户变量,则启动这些路由,否则它将停留在登录页面 。我在我的项目中实现了这个。

      return (
        <div>
          <Notification notification={notification} type={notificationType} />
    
          {
            user === null &&
            <LoginForm startLogin={handleLogin} />
          }
    
          {
            user !== null &&
            <NavBar user={user} setUser={setUser} />
          }
    
          {
            user !== null &&
            <Router>
              <Routes>
                <Route exact path="/" element={<Home />} />
                <Route exact path="/adduser" element={<AddUser />} /> />
                <Route exact path="/viewuser/:id" element={<ViewUser />} />
              </Routes>
            </Router>
          }
    
        </div>
      )
    
  • import { BrowserRouter as Router } from "react-router-dom";        
    import { Routes, Route } from "react-router-dom";      
    import Home from "./component/home/Home.js";      
    import Products from "./component/Products/Products.js";      
    import Profile from "./component/user/Profile.js";      
          
    import ProtectedRoute from "./component/Route/ProtectedRoute";      
    function App() {      
     return (      
        <Router>      
        <Routes>      
            <Route path="/" element={<Home />} />      
            <Route path="/products" element={<Products />} />      
            <Route      
              path="/account"      
              element={      
                <ProtectedRoute  >      
                  <Profile />      
                </ProtectedRoute>      
              }      
            />      
          </Routes>      
           </Router>      
      );      
    }      
          
    //ProtectedRoute       
    
    export default App;      
    import React from "react";      
    import { useSelector } from "react-redux";      
    import { Navigate } from "react-router-dom";      
    
    function ProtectedRoute({ children }) {      
      const { isAuthecated, loading } = useSelector((state) => state.user);      
          
      if (!isAuthecated) {      
        return <Navigate to="/login" replace />;      
      }      
      return children;      
    }      
    export default ProtectedRoute;      
          
    
  • 引用 13

    就目前的情况来看,您的答案不够清晰。请编辑以添加更多详细信息,帮助其他人了解此内容如何解决所提问题。您可以在帮助中心找到有关如何撰写良好答案的更多信息。

  • import { v4 as uuidv4 } from "uuid";
    
    const routes = [
        {
            id: uuidv4(),
            isProtected: false,
            exact: true,
            path: "/home",
            component: param => <Overview {...param} />,
        },
        {
            id: uuidv4(),
            isProtected: true,
            exact: true,
            path: "/protected",
            component: param => <Overview {...param} />,
            allowed: [...advanceProducts], // subscription
        },
        {
            // if you conditional based rendering for same path
            id: uuidv4(),
            isProtected: true,
            exact: true,
            path: "/",
            component: null,
            conditionalComponent: true,
            allowed: {
                [subscription1]: param => <Overview {...param} />,
                [subscription2]: param => <Customers {...param} />,
            },
        },
    ]
    
    // Navigation Component
    import React, { useEffect, useState } from "react";
    import { useSelector } from "react-redux";
    import { Switch, Route, useLocation } from "react-router-dom";
    
    // ...component logic
    <Switch>
        {routes.map(params => {
            return (
                <ProtectedRoutes
                    exact
                    routeParams={params}
                    key={params.path}
                    path={params.path}
                />
            );
        })}
        <Route
            render={() => {
                props.setHideNav(true);
                setHideHeader(true);
                return <ErrorPage type={404} />;
            }}
        />
    </Switch>
    
    // ProtectedRoute component
    import React from "react";
    import { Route } from "react-router-dom";
    import { useSelector } from "react-redux";
    
    const ProtectedRoutes = props => {
        const { routeParams } = props;
        const currentSubscription = 'xyz'; // your current subscription;
        if (routeParams.conditionalComponent) {
            return (
                <Route
                    key={routeParams.path}
                    path={routeParams.path}
                    render={routeParams.allowed[currentSubscription]}
                />
            );
        }
        if (routeParams.isProtected && routeParams.allowed.includes(currentSubscription)) {
            return (
                <Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
            );
        }
        if (!routeParams.isProtected) {
            return (
                <Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
            );
        }
        return null;
    };
    
    export default ProtectedRoutes;

    想要添加亮点永远不要忘记将路径作为 prop 提供给 ProtectedRoute,否则它将不起作用。

  • 这是一个简单的 react-router v6 保护路由。我把所有想要保护的路由都放在 : 中 routes.js -

    const routes = [{ path: "/dasboard", name:"Dashboard", element: <Dashboard/> }]
    

    要呈现路线,只需按如下方式映射它们:-

    <Routes>
       {routes.map((routes, id) => {
         return(
         <Route
             key={id}
             path={route.path}
             exact={route.exact}
             name={route.name}
             element={
                localStorage.getItem("token") ? (
                    route.element
                 ) : (
                    <Navigate to="/login" />
                 )
             }
         )
       })
      }
    </Routes>
    
返回
作者最近主题: