文章
问答
冒泡
基于react-router-dom的登录认证状态控制

在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,则会跳转到登录页。

react-router-dom

关于作者

落雁沙
非典型码农
获得点赞
文章被阅读