提问人:learner62 提问时间:2/20/2021 最后编辑:Drew Reeselearner62 更新时间:9/19/2023 访问量:30874
如何使用 react-router-dom 创建受保护的路由?
How to create a protected route with react-router-dom?
问:
如何使用 localStorage 创建受保护的路由并将其存储在 localStorage 中,以便当用户下次尝试打开时,他们可以再次查看其详细信息。登录后,他们应重定向到仪表板页面。react-router-dom
所有功能都添加到 ContextApi 中。 Codesandbox link : 代码
我尝试过但未能实现
“路由”页
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>
);
}
}
答:
问题
<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
6 版
在版本 6 中,自定义路由组件已失宠,首选方法是使用身份验证布局组件。
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
5 版
创建一个使用身份验证上下文的组件。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>
);
}
评论
PrivateRoute
对于 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
评论
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;
想要添加突出显示,永远不要忘记将路径作为 ProtectedRoute 的道具,否则它将无法正常工作。
这是一个简单的 react-router v6 保护路由。我已经将所有要保护的路由放在路由.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>
如果您想要一种简单的实现方法,请使用 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;
评论
这个答案是针对 reactjs 的新版本
React 路由器 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;
};
评论