需求
未登录状态
下,某些页面不可访问,白名单
中的页面可以。未登录状态
下,拦截通过修改url直接访问页面。- 判断是否
有权
访问某些页面。 - 路由规则中每个页面都需要调用某个接口。
前提
使用的react-router-dom6 ,这里只是举例,具体细节根据项目调整。
路由表生成路由规则
import { Navigate, Outlet, RouteObject, useRoutes } from "react-router-dom"import MyLayout from "@/layout/index"
// 无需Layout的组件
import Login from "@/views/Login/Login"
import NotFound from "@/views/NotFound/NotFound"
// 组件
import Dashboard from "@/views/Dashborad/Dashboard"
import Project from "@/views/Project/Project"
import Test1 from "@/views/Setting/Test1"
import Test2 from "@/views/Setting/Test2"
import Test3 from "@/views/Test/Test3"
import Test4 from "@/views/Test/Test4"const router_items: RouteObject[] = [{path: "/",element: <MyLayout />,children: [{path: "",element: <Navigate to="/dashboard" />, // 重定向},{path: "dashboard",element: <Dashboard />,},{path: "project",element: <Project />,},{path: "setting",element: <Outlet />, // 占位符children: [{ path: "test1", element: <Test1 /> },{ path: "test2", element: <Test2 /> },],},{path: "test",element: <Outlet />, // 占位符children: [{ path: "test3", element: <Test3 /> },{ path: "test4", element: <Test4 /> },],},],},// 不需要layout的页面写到外面{path: "login",element: <Login />,},{ path: "*", element: <NotFound /> },
]export default () => {// 根据路由表生成对应的路由规则const ElementRouter = useRoutes(router_items)return ElementRouter
}
上述路由规则会在<MyLayout />中声明的位置处展示
APP中注册路由
// 路由
import GetRouter from "./router"function App() {const RouterElement = GetRouter()return <>{RouterElement}</>
}export default App
实现步骤
先创建高阶组件
名为AuthRouter,并在main.tsx中引入并包裹APP。
高阶组件指接收一个组件并返回增强后的该组件。
AuthRouter
const AuthRouter = (props: { children: JSX.Element }) => {return props.children
}export default AuthRouter
import ReactDOM from "react-dom/client"
import App from "./App.tsx"
import "./index.scss"
// router
import { BrowserRouter as Router } from "react-router-dom"
import AuthRouter from "@/HOC/AuthRouter.tsx" // 高阶组件ReactDOM.createRoot(document.getElementById("root")!).render(<Router><AuthRouter><App /></AuthRouter></Router>
)
token相关
一、token失效重定向到login
AuthRouter
import { Navigate, useLocation } from "react-router-dom"const AuthRouter = (props: { children: JSX.Element }) => {const { pathname } = useLocation()let token = "sdnfowe623ognis"if (pathname === "/login") {return props.children}if (!token) {return <Navigate to="/login" replace />} else {return props.children}
}export default AuthRouter
二、白名单无需判断token
AuthRouter
import { Navigate, useLocation } from "react-router-dom"const AuthRouter = (props: { children: JSX.Element }) => {const { pathname } = useLocation()const whiteList = ["/login", "/test/test4"] // 声明白名单let token = "sdnfowe623ognis"// 白名单直接放行if (whiteList.includes(pathname)) { return props.children}if (!token) {return <Navigate to="/login" replace />} else {return props.children}
}export default AuthRouter
权限相关
基本同白名单
逻辑
AuthRouter
import { useLocation } from "react-router-dom"const AuthRouter = (props: { children: JSX.Element }) => {const { pathname } = useLocation()let auth_list = ["/login", "/dashboard"] // 权限只能访问这些路由if (!auth_list.includes(pathname)) {return (<div><h2>暂无权限</h2></div>)}return props.children
}export default AuthRouter
当访问无权路由时,展示如下:
每个页面都需要调用的函数
假如某些接口数据作用于全局且总会改变,如用户信息等,也可以写到AuthRouter中。
注意
:只有处于登录态
且需要调用
该函数的路由,才能调用。
AuthRouter
import { Navigate, useLocation } from "react-router-dom"
import API from "@/api"const AuthRouter = (props: { children: JSX.Element }) => {const { pathname } = useLocation()// 不需要获取用户信息的路由const notGetUserInfoRouteList: string[] = ["/login","/register","/test/test4",]let token = "dsnfoiwne23"if (!token) {return <Navigate to="/login" replace />} else {// 有token 且 需要调用if (!notGetUserInfoRouteList.includes(pathname)) {API.getUserInfo().then(({ code, data }) => {...})}return props.children}
}export default AuthRouter
上面的API是封装好的请求,具体可看另一篇文章:TS封装axios并约束请求参数以及响应的类型
整体代码
import { Navigate, useLocation } from "react-router-dom"
import cookie from "react-cookies"
import API from "@/api"const AuthRouter = (props: { children: JSX.Element }) => {const { pathname } = useLocation()const whiteList: string[] = ["/login", "/test/test4"] // 白名单(无需登录)const noUserInfoList: string[] = [...whiteList, "/register"] // 不需要调用 getuserinfo 的路由const authList: string[] = ["/login", "/dashboard"] // 权限只能访问这些路由if (!authList.includes(pathname)) {return (<div><h2>无权访问该页面</h2></div>)}// 如果当前路由不在白名单中,且没有 token,则重定向到登录页if (!whiteList.includes(pathname) && !cookie.load("token")) {return <Navigate to="/login" replace />}// 如果当前路由需要调用 getuserinfo 接口,就调用它if (!noUserInfoList.includes(pathname)) {API.getUserInfo().then(({ code, data }) => {...})}// 返回子组件return props.children
}export default AuthRouter