[英]Restricted navigation React Router Dom - Private and Public routes
I need to make a router system that distinguishes between authenticated and non-authenticated users.我需要制作一个区分经过身份验证和未经身份验证的用户的路由器系统。
What I want to achieve with this is that authed users can see their dashboard and personal details, but unauthed users can only see the landing page, the login form and the register form.我想要实现的是,经过身份验证的用户可以看到他们的仪表板和个人详细信息,但未经身份验证的用户只能看到登录页面、登录表单和注册表单。
I currently have context management so I know whether a user is logged in or not.我目前有上下文管理,所以我知道用户是否登录。 I just need to figure out all the redirects and routing related things.
我只需要弄清楚所有重定向和路由相关的事情。
My code is making all sorts of "strange" things.我的代码正在制作各种“奇怪”的东西。 I don't really know where I have messed it up.
我真的不知道我在哪里搞砸了。
This is where all the routing happens.这是所有路由发生的地方。
AppLayout
is just a layout wrapper with a header and a footer that must be visible only when logged in. AppLayout
只是一个布局包装器,带有 header 和一个仅在登录时才可见的页脚。
const AppContent = () => (
<Router>
<Switch>
<PublicRoute component={() => (<h1>Landing page</h1>)} path='/' exact />
<PublicRoute component={LoginPage} path='/login' exact />
<PublicRoute component={() => (<h1>Register page</h1>)} path='/register' exact />
<PrivateRoute component={Home} path='/dashboard' exact />
<PrivateRoute component={Demo} path='/demo' exact />
<PrivateRoute component={Profile} path='/profile' exact />
<PublicRoute component={() => (<h1>not found</h1>)} path='*' />
<PrivateRoute component={() => (<h1>not found</h1>)} path='*' />
</Switch>
</Router>
);
const PublicRoute = ({ component: Component, ...rest }) => {
const { user, isLoading } = useContext(AuthContext);
if (isLoading) {
return (
<h1>Loading...</h1>
);
}
return (
<Route {...rest} render={(props) => (user ? <Redirect to='/dashboard' /> : <Component {...props} />)} />
);
};
const PrivateRoute = ({ component: Component, ...rest }) => {
const { user, isLoading } = useContext(AuthContext);
if (isLoading) {
return (
<h1>Loading...</h1>
);
}
return (
<Route
{...rest}
render={(props) => (user ? (
<AppLayout>
<Component {...props} />
</AppLayout>
) : <Redirect to='/login' />)}
/>
);
};
This is where I manage my auth context.这是我管理身份验证上下文的地方。
const AuthStore = ({ children }) => {
const [token, setToken] = useState();
const [user, setUser] = useState();
const [isLoading, setIsLoading] = useState(false);
const setUserToken = async (userToken) => {
localStorage.setItem('token', userToken);
setToken(userToken);
try {
const decodedToken = jwtDecode(userToken);
const currentUserData = await AuthService.getUserData(decodedToken.username);
setUser(currentUserData);
} catch (error) {
console.log(error.name);
}
};
useEffect(() => {
setIsLoading(true);
const localToken = localStorage.getItem('token');
if (localToken) {
setUserToken(localToken);
}
setIsLoading(false);
}, []);
return (
<AuthContext.Provider value={{
user, token, setUserToken, setUser, isLoading,
}}
>
{children}
</AuthContext.Provider>
);
};
Thank you so much.太感谢了。
What I am really looking for: When Unauthorized:我真正在寻找什么: 未经授权时:
/dashboard
, redirect to /login
✅/dashboard
时,重定向到/login
✅/login
✅/login
✅/register
, redirect to it fine ✅/register
,重定向到它就好✅ When Authorized:授权时:
/login
, redirect to /dashboard
✅/login
时,重定向到/dashboard
✅<PrivateRoute component={() => (<h1>not found</h1>)} path='*'
✅<PrivateRoute component={() => (<h1>not found</h1>)} path='*'
✅/profile
, redirect to it fine ❌ ➡️ It is currently reloading the routes, showing the login page and after half a second it shows /dashboard
, but not /profile
/profile
,重定向到它很好 ❌ ➡️ 它当前正在重新加载路由,显示登录页面,半秒后显示/dashboard
,但不显示/profile
According to React Router documentation, direct children of <Switch>
component can only be <Route>
or <Redirect>
components from react-router-dom package.根据React Router文档,
<Switch>
组件的直接子级只能是 react-router-dom package 中的<Route>
或<Redirect>
组件。
All children of a <Switch> should be <Route> or <Redirect> elements. Only the first child to match the current location will be rendered.
Your <AppLayout />
component is the problem.您的
<AppLayout />
组件是问题所在。 Remove it from <Switch>
and move it inside your auth pages.从
<Switch>
中删除它并将其移动到您的身份验证页面中。
edit编辑
your auth provider is going trough async flow anytime you type in a new address in the browser and press enter, meaning every time you will have a state in your app where user is not logged in, then the components that are consuming this state are reacting to your change.每当您在浏览器中输入新地址并按 Enter 键时,您的身份验证提供程序都会进入异步流程,这意味着每次您的应用程序中都会有一个 state 且用户未登录,那么使用此 state 的组件就会做出反应到你的改变。 also in the effect you should
await
setUserToken because loading is set to false before that async function resolves.同样,您应该
await
setUserToken 因为在异步 function 解析之前加载设置为 false。
the last thing that is not working on your list is because you coded it like that;), your public route redirects all calls it receives to the /dashboard
if there is user
, regardless if it should be a 404 route or existing route.最后一件事在您的列表中不起作用是因为您这样编码;),如果有
user
,您的公共路由会将它收到的所有呼叫重定向到/dashboard
,无论它应该是 404 路由还是现有路由。 i would suggest different approach.我会建议不同的方法。 create a config where you declare if route is protected or not, then have only one AuthRoute component that will take all the props of the route, and based on this new flag and state of user in the context, do the work
创建一个配置,在其中声明路由是否受保护,然后只有一个 AuthRoute 组件将获取路由的所有道具,并基于上下文中用户的这个新标志和 state,完成工作
const routes = [{ name: 'home', path: '/', exact: true, isProtected: false, component: Home }, { name: 'protected', path: '/dashboard', exact: true, isProtected: true, component: Dashboard }];
const AuthRoute = ({ name, path, exact, isProtected, component: Component }) => {
const { user } = useContext(userContext);
if (isProtected && !user) { // redirect to login }
if (!isProtected || (isProtected && user)) { // render route with props }
}
///...
<Switch>
{routes.map(route => <AuthRoute {...route} />
</Switch>
I was facing the same problems just 3 to 4 days back when a very kind person who is just amazing, helped me out on the reactiflux server of discord.就在 3 到 4 天前,我遇到了同样的问题,当时一个非常善良的人非常了不起,在 discord 的 reactiflux 服务器上帮助了我。 You might be trying to go to one protected route and that would work but the other protected route will not work right??
您可能正在尝试 go 到一条受保护的路线,这会起作用,但另一条受保护的路线不起作用? All you have to do is create a Higher Order Component (HOC) in a separate file which you can maybe call
protectedRoute.js
and inside this file:您所要做的就是在一个单独的文件中创建一个高阶组件 (HOC),您可以调用
protectedRoute.js
并在此文件中:
import React, { useState, useEffect } from "react";
import { Redirect } from "react-router-dom";
export function protectedRoute(Component) {
return function ComponentCheck(props) {
const [check, setCheck] = useState(false);
const [currentUser, setCurrentUser] = useState(false);
useEffect(() => {
const user = false;
setCurrentUser(user);
setCheck(true);
}, []);
const RedirectToLogin = <Redirect to="/" />;
return check && (currentUser ? <Component {...props} /> : RedirectToLogin);
};
}
In the above file the '/' route in my case is the login page but instead of const RedirectToLogin = <Redirect to='/' />
you can say const RedirectToLogin = <Redirect to='/login' />
在上面的文件中,'/' 路径在我的例子中是登录页面,但是你可以说
const RedirectToLogin = <Redirect to='/login' />
而不是const RedirectToLogin = <Redirect to='/' />
'/' />
and then you can restrict a route like for example I want the /users
route to be accessible only if user === true
.然后你可以限制一个路由,例如我希望
/users
路由只有在user === true
时才能访问。 So for that i can in the users.js
file say:因此,我可以在
users.js
文件中说:
import { protectedRoute } from "./protectedRoute";
const Users = () => {
return <h2>Users</h2>;
};
export default protectedRoute(Users);
and then I also want the /dashboard
route to be protected so:然后我还希望
/dashboard
路由受到保护:
import { protectedRoute } from "./protectedRoute";
const Dashboard = () => {
return <h2>Dashboard</h2>;
};
export default protectedRoute(Dashboard);
but I dont want the /home
route to be protected so:但我不希望
/home
路由受到保护,所以:
const Home = () => {
return <h2>Home</h2>;
};
export default Home;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.