在react-router-dom中,没有像vue-router的路由守卫,所以这个功能如果要用,就需要自己来实现了。
官方提供了一个简单的demo来实现身份认证的路由,https://reactrouter.com/web/example/auth-workflow 官方的demo是基于context来实现的。我们工程使用的是mobex,所以这里以mobx为例来实现。
首先,我们要对route进行一下封装
auth-route.jsx
import {inject, observer} from "mobx-react";
import {Redirect, Route} from "react-router"
import React, {useEffect, useState} from "react"
import {administratorApi} from "../../apis/administrator";
import {Spin} from "antd";
const AuthRouteComponent = ({children, ctxStore, component, ...rest}) => {
const {visitor, setVisitor} = ctxStore;
const [synced, setSynced] = useState(false); //是否已经从服务端同步过用户信息
//region 如果是页面刷新的时候,mobx中的visitor并未赋值,此处同步去服务端获取下访问者信息
useEffect(async () => {
if (!visitor) {
await administratorApi.queryVisitor().then((res) => {
setVisitor(res);
}).finally(() => {
setSynced(true);
});
}
}, [visitor]);
//endregion
const handleRender = (routeProps) => {
Object.assign(routeProps,{route: rest.route})
return visitor ? (<>
{children || React.createElement(component, {...routeProps})}
</>) : (synced ? <Redirect to={{
pathname: "/sign-in",
state: {from: routeProps.location}
}}/> : <div style={{width:'100%'}}><Spin/></div>)
};
return <Route {...rest} render={handleRender}/>
}
const AuthRoute = inject('ctxStore')(observer(AuthRouteComponent))
export default AuthRoute
可以看到,这里的逻辑是,当mobx中的visitor无数据的时候,就会去请求服务端,获取当前登录用户的信息。如果没有访问者信息,并且已经到服务端同步过,就重定向到登录页面。
考虑到代码的可维护性,我们同样来写一个route-config
auth-react-router-config.jsx
import AuthRoute from "./auth-route";
import {Route} from "react-router-dom";
export const renderRoutes = (routes = [],extraProps={},switchProps={}) => {
return <>
<Switch {...switchProps}>
{routes && routes.map((route,i) => {
if (route.anonymous) {
return <Route
key={route.key || i}
path={route.path}
exact={route.exact}
strict={route.strict}
render={props =>
route.render ? (
route.render({ ...props, ...extraProps, route: route })
) : (
<route.component {...props} {...extraProps} route={route} />
)
}
/>
} else {
Object.assign(route,{route});
return <AuthRoute {...route} />
}
})}
</Switch>
</>
}
在管理后台的工程上,基本都的要认证的,所以我们配置的匿名用户登录的。
routes的文件改成这样
export default [
{path: `/sign-in`, component: SignInView,anonymous: true},
{
path: '/', component: AdminLayout, routes: [
{path: '/user-list', component: UserListView},
{path: '/article-draft-list', component: ArticleDraftListView},
{path: '/question-draft-list', component: QuestionDraftView},
{path: '/resource-list', component: ResourceListView},
{path: '/api-list', component: ApiListView}
]
}
];
这样就会在路由跳转的时候,先进行登录认证,如果没有登录信息,也没有token,则会跳转到登录页。