React.js 简单的基于角色的路由
React.js Simple Role Based Routes
这是我第一次使用基于角色的路由。我们为玩家提供了一个功能完备的应用程序。现在,我们需要为该应用程序添加 Trainer 页面。我们将用户存储在 Firebase 中,我们需要手动为用户添加新密钥,例如 trainer: true|false
。在 React Application 中,我们将重定向用户。
例如:
if (user.trainer) {
<Redirect to={"/trainer"}
} else {
<Redirect to={"/"}
}
并且我们需要管理其他页面。例如:当培训师想要导航到另一个不允许的页面时,我们需要将他们重定向回 "/trainer"
或对面的普通玩家无法导航到 "/trainer"
页面。有人可以帮我吗?
我有这样的集中路由;
import SignInSignUp from "./pages/SignInSignUp/SignInSignUp";
import Home from "./pages/Home/Home";
import Help from "./pages/Help/Help";
import Profile from "./pages/Profile/Profile";
import Exercises from "./pages/Exercises/Exercises";
import Trainer from "./pages/Trainer/Trainer";
export const routes = [
{ isProtected: false, path: "/auth", component: SignInSignUp },
{ isProtected: true, path: "/", component: Home },
{ isProtected: true, path: "/help", component: Help },
{ isProtected: true, path: "/profile", component: Profile },
{ isProtected: true, path: "/exercises", component: Exercises },
{ isProtected: true, path: "/trainer", component: Trainer },
];
然后我就这样循环路由;
import "./App.scss";
import { Switch, Route, Redirect } from "react-router-dom";
import Navbar from "./components/Navbar/Navbar";
import ProtectedRouter from "./utils/ProtectedRouter";
import { routes, navbarPaths } from "./routes";
function App() {
return (
<div className="App">
<Switch>
{routes.map(
({
isProtected,
component,
path,
}: {
isProtected: boolean;
component: any;
path: string;
}) => {
const RouteWrapper = isProtected ? ProtectedRouter : Route;
return (
<RouteWrapper
exact
key={path}
path={path}
component={component}
/>
);
}
)}
<Route exact path="/player*" render={() => (<Redirect to={"/"} />)} />
</Switch>
<Route path={navbarPaths} exact component={Navbar} />
</div>
);
}
export default App;
这是我的受保护路由组件
import { Route, Redirect } from "react-router-dom";
import { useAuthStatus } from "../firebase/useAuthStatus.hook";
const ProtectedRouter = ({ component: Component, ...rest }: any) => {
const { loggedIn, checkingStatus } = useAuthStatus();
return (
<Route
{...rest}
render={(props) => {
if (!checkingStatus) {
if (loggedIn) {
return <Component />;
} else {
return (
<Redirect
to={{
pathname: "/auth",
state: {
from: props.location,
},
}}
/>
);
}
}
}}
/>
);
};
export default ProtectedRouter;
如果我没有正确理解你的问题,你想根据用户的角色有条件地更改 ProtectedRouter
组件中的重定向目标。
完全没有测试,但我相信以下内容会解决您的问题。
重构您的 ProtectedRoute
以采用 isProtected
、trainer
和传递的路线道具。如果路由未受保护,请检查用户的 trainer
角色是否匹配,并有条件地呈现路由或重定向到 "/trainer"
或 "/"
。如果路由受保护 并且 用户已通过身份验证,请再次检查用户的 trainer
角色是否匹配并有条件地呈现路由或重定向到 "/trainer"
或 "/"
.
const ProtectedRouter = ({ isProtected, trainer, ...props }: any) => {
const location = useLocation();
const { loggedIn, checkingStatus } = useAuthStatus();
const user = /* business logic to get user object */
if (checkingStatus) return null;
if (!isProtected || loggedIn) {
return user.trainer === trainer
? <Route {...props} />
: <Redirect to={user.trainer ? "/trainer" : "/"} />;
}
return (
<Redirect
to={{
pathname: "/auth",
state: { from: location },
}}
/>
);
};
更新 routes
以添加 trainer
属性。
export const routes = [
{ isProtected: false, path: "/auth", component: SignInSignUp },
{ isProtected: true, path: "/", component: Home },
{ isProtected: true, path: "/help", component: Help },
{ isProtected: true, path: "/profile", component: Profile },
{ isProtected: true, path: "/exercises", component: Exercises },
{ isProtected: true, path: "/trainer", component: Trainer, trainer: true },
];
更新 App
以将所有路由映射到自定义路由组件。
function App() {
...
return (
<div className="App">
<Switch>
{routes.map(props => <ProtectedRouter key={props.path} exact {...props} />)}
<Route exact path="/player*" render={() => (<Redirect to={"/"} />)} />
</Switch>
<Route path={navbarPaths} exact component={Navbar} />
</div>
);
}
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 (
<Route
render={() => {
return <ErrorPage type={404} />;
}}
/>
);
};
export default ProtectedRoutes;
想要添加亮点永远不要忘记将路径作为 ProtectedRoute 的属性,否则将无法工作。
这是我第一次使用基于角色的路由。我们为玩家提供了一个功能完备的应用程序。现在,我们需要为该应用程序添加 Trainer 页面。我们将用户存储在 Firebase 中,我们需要手动为用户添加新密钥,例如 trainer: true|false
。在 React Application 中,我们将重定向用户。
例如:
if (user.trainer) {
<Redirect to={"/trainer"}
} else {
<Redirect to={"/"}
}
并且我们需要管理其他页面。例如:当培训师想要导航到另一个不允许的页面时,我们需要将他们重定向回 "/trainer"
或对面的普通玩家无法导航到 "/trainer"
页面。有人可以帮我吗?
我有这样的集中路由;
import SignInSignUp from "./pages/SignInSignUp/SignInSignUp";
import Home from "./pages/Home/Home";
import Help from "./pages/Help/Help";
import Profile from "./pages/Profile/Profile";
import Exercises from "./pages/Exercises/Exercises";
import Trainer from "./pages/Trainer/Trainer";
export const routes = [
{ isProtected: false, path: "/auth", component: SignInSignUp },
{ isProtected: true, path: "/", component: Home },
{ isProtected: true, path: "/help", component: Help },
{ isProtected: true, path: "/profile", component: Profile },
{ isProtected: true, path: "/exercises", component: Exercises },
{ isProtected: true, path: "/trainer", component: Trainer },
];
然后我就这样循环路由;
import "./App.scss";
import { Switch, Route, Redirect } from "react-router-dom";
import Navbar from "./components/Navbar/Navbar";
import ProtectedRouter from "./utils/ProtectedRouter";
import { routes, navbarPaths } from "./routes";
function App() {
return (
<div className="App">
<Switch>
{routes.map(
({
isProtected,
component,
path,
}: {
isProtected: boolean;
component: any;
path: string;
}) => {
const RouteWrapper = isProtected ? ProtectedRouter : Route;
return (
<RouteWrapper
exact
key={path}
path={path}
component={component}
/>
);
}
)}
<Route exact path="/player*" render={() => (<Redirect to={"/"} />)} />
</Switch>
<Route path={navbarPaths} exact component={Navbar} />
</div>
);
}
export default App;
这是我的受保护路由组件
import { Route, Redirect } from "react-router-dom";
import { useAuthStatus } from "../firebase/useAuthStatus.hook";
const ProtectedRouter = ({ component: Component, ...rest }: any) => {
const { loggedIn, checkingStatus } = useAuthStatus();
return (
<Route
{...rest}
render={(props) => {
if (!checkingStatus) {
if (loggedIn) {
return <Component />;
} else {
return (
<Redirect
to={{
pathname: "/auth",
state: {
from: props.location,
},
}}
/>
);
}
}
}}
/>
);
};
export default ProtectedRouter;
如果我没有正确理解你的问题,你想根据用户的角色有条件地更改 ProtectedRouter
组件中的重定向目标。
完全没有测试,但我相信以下内容会解决您的问题。
重构您的 ProtectedRoute
以采用 isProtected
、trainer
和传递的路线道具。如果路由未受保护,请检查用户的 trainer
角色是否匹配,并有条件地呈现路由或重定向到 "/trainer"
或 "/"
。如果路由受保护 并且 用户已通过身份验证,请再次检查用户的 trainer
角色是否匹配并有条件地呈现路由或重定向到 "/trainer"
或 "/"
.
const ProtectedRouter = ({ isProtected, trainer, ...props }: any) => {
const location = useLocation();
const { loggedIn, checkingStatus } = useAuthStatus();
const user = /* business logic to get user object */
if (checkingStatus) return null;
if (!isProtected || loggedIn) {
return user.trainer === trainer
? <Route {...props} />
: <Redirect to={user.trainer ? "/trainer" : "/"} />;
}
return (
<Redirect
to={{
pathname: "/auth",
state: { from: location },
}}
/>
);
};
更新 routes
以添加 trainer
属性。
export const routes = [
{ isProtected: false, path: "/auth", component: SignInSignUp },
{ isProtected: true, path: "/", component: Home },
{ isProtected: true, path: "/help", component: Help },
{ isProtected: true, path: "/profile", component: Profile },
{ isProtected: true, path: "/exercises", component: Exercises },
{ isProtected: true, path: "/trainer", component: Trainer, trainer: true },
];
更新 App
以将所有路由映射到自定义路由组件。
function App() {
...
return (
<div className="App">
<Switch>
{routes.map(props => <ProtectedRouter key={props.path} exact {...props} />)}
<Route exact path="/player*" render={() => (<Redirect to={"/"} />)} />
</Switch>
<Route path={navbarPaths} exact component={Navbar} />
</div>
);
}
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 (
<Route
render={() => {
return <ErrorPage type={404} />;
}}
/>
);
};
export default ProtectedRoutes;
想要添加亮点永远不要忘记将路径作为 ProtectedRoute 的属性,否则将无法工作。