前端路由权限解决方案

135 阅读2分钟

我的博客原文

@author 郭瑞峰 @createTime 2023/06/18 @updateTime 2023/06/20

前言

好久没写文章了,还是写一些解决方案吧,不然会很尴尬 ㄟ( ▔, ▔ )ㄏ

啥是路由权限

先说大白话哈,路由权限就是不能去的地方坚决不能去,能去的地方马上放行

解决方案

目前我的解决方案为两种:

  • 全部加载后再判断
  • 后端提供“名单”后重新加载

全部加载后再判断

顾名思义,所有路由加载进来,对每一个路由进行校验

  • vue-router 方案
// vue-router 配置
import { createRouter,createWebHashHistory, type RouteRecordRaw } from 'vue-router'


const routes: RouteRecordRaw[] = [
    {
      path: '/',
      component: () => import('../components/HelloWorld.vue'),
      meta: {
        isAuth: false
      }
    },
    {
      path: '/aaa',
      component: () => import('../components/aaa.vue'),
      meta: {
        isAuth: true
      }
    }
]

const router = createRouter({
    routes: routes,
    history: createWebHashHistory()
})

router.beforeEach((to, from, next) => {
  if (!to.meta.isAuth) {
    // 无需认证,直接放行
    next()
  } else {
    // 认证
	if (......认证通过) { next() }
	// 认证失败
    next(from)
  }
})

export default router

  • react-router 暂时不建议这样操作

后端提供“名单”后重新加载

后端请求完数据后,前端渲染

  • vue + pinia + vue-router 的解决方案
import { defineStore } from 'pinia'
import { useRouter } from 'vue-router'

const indexStore = defineStore('index', () => {
  const getRoutes = (): void => {
    fetch('xxxxxxx')
    .then(response => response.json())
    .then(({ data }: any) => {
// 这里添加后端返还的路由


      const $router = useRouter()
      data.forEach(({parentName, route}) => {
	    // 后端可以提供名单,也可以只提供 string[] ,让前端自己匹配名单
        $router.addRoute(parentName, route)
      });



    })
    .catch(() => {
      ......
    })
  }
  return {
    getRoutes
  }
})

export default indexStore
  • react + react-router
// router.tsx
import React from 'react'
import { type RouteObject } from 'react-router-dom'
import MyLayout from '../components/organisms/MyLayout'
import Aaa from '../pages/app/aaa'
import A2 from '../pages/app/a2'
import { nestComponents } from '../utils/routesUtils'

const routeDict: Record<string, RouteObject> = {
  app: { path: '/app', element: (<MyLayout/>) },
  appTest: { path: '/app/test', element: (nestComponents([MyLayout, Test])) },
  appAaa: { path: '/app/aaa', element: (nestComponents([MyLayout, Aaa])) },
  appA2: { path: '/app/a2', element: (nestComponents([MyLayout, A2])) }
}

const getRoute = (dict: string[]): RouteObject[] => {
  if (dict.length === 0) { return [] }

// 这里应该写个默认值,防止后端提供字符串没有匹配上
  return dict.map(item => routeDict[item])
}
import React, { useState } from 'react'
import { BrowserRouter, Routes, Route } from 'react-router'
import getRoute from './router.tsx'

const App: React.FC = () => {
  const [routes, getRoutes] = useState<string[]>([])
  // 获取路由
  ........
  return (
    <BrowserRouter>
      <Routes>
        {
		  // 根据字典加载路由
		  getRoute().map(item => (
            <Route key={item.path} path={item.path} element={item.element} />
          ))
		}
      </Routes>
    </BrowserRouter>
	)
}

App.displayName = 'App'
export default App

27780996_0_final.png