需求
未登录状态
下,某些页面不可访问,白名单
中的页面可以。未登录状态
下,拦截通过修改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