vue3项目中使用权限仓库&路由守卫

示例前提:路由数组配置时,拆分成静态路由和动态路由,导出时配置的静态路由

定义用户信息仓库(hooks语法)

import { defineStore } from "pinia";
const useUserStore = defineStore('userStore', () => {

  这里是一些获取用户数据,储存数据的代码...省略...
  
      return {
        token, // 用户token
        role, // 用户角色
        userInfo, // 用户信息
        MyLogin, // 登陆方法
        MyGetUserInfo, // 获取用户信息方法
        ClearInfo // 清除信息数据
    } 
})
export default useUserStore
}

定义权限仓库文件

import { defineStore } from "pinia";
// 引入声明文件中自己定义的ts约束类型 
import { MyRoutes, MyRoute } from "~/my-router";
// 引入静态路由和动态路由
import { constanceRoutes, asyncRoutes } from "@/router";

export const usePermissionStore = defineStore('permissionStore', () => {
    // 是否获取用户信息
    const isGetUserInfo = ref(false)

    // 最终给导航栏使用的路由数组
    const navRoutes = ref<MyRoutes>([])

    // 修改用户信息状态
    function setUserInfoState(flag: boolean) {
        isGetUserInfo.value = flag
    }

    // 判断单个路由权限,返回布尔值
    function hasPermission(route: MyRoute, role: string) {
        // meta上有设置roles时则需要判断权限
        if (route.meta?.roles) {
            return route.meta.roles.includes(role)
        }
        // 没有设置roles时则有权限
        return true
    }

    // 判断多个路由权限,并筛选出有权限的路由数组
    function filterAsyncRoutes(routes: MyRoutes, role: string) {
        // 创建临时路由数组
        const tempArr: MyRoutes = []
        // 遍历传入的多个路由数组
        routes.forEach(route => {
            // 遍历出来的单个路由判断是否有权限(外层)
            if (hasPermission(route, role)) {
                // 如果有children,则递归遍历赋值(内层)
                if (route.children && route.children.length > 0) {
                    route.children = filterAsyncRoutes(route.children, role)
                }
                // 有权限则添加该路由
                tempArr.push(route)
            }
        })
        // 返回筛选后的路由数组
        return tempArr
    }

    // 生成动态路由
    function generateRoute(role: string) {
        // 使用异步便于控制
        return new Promise<MyRoutes>(resolve => {
            // 传入我们自己分组的动态路由,筛选出符合角色身份的路由数组
            const accessRoutes = filterAsyncRoutes(asyncRoutes, role)
            // 将静态路由和新的动态路由拼接
            navRoutes.value = [...constanceRoutes, ...accessRoutes]
            resolve(accessRoutes)
        })
    }

    return {
        isGetUserInfo,
        navRoutes,
        setUserInfoState,
        generateRoute
    }
})

export default usePermissionStore

路由权限守卫

  1. 安装滚动条插件
yarn add nprogress
yarn add @types/nprogress
  1. 配置路由守卫
// 引入滚动条及样式
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

// 引入路由
import router from "./router";
// 引入权限仓库
import usePermissionStore from "./store/permissionStore";
// 引入用户信息仓库
import useUserStore from "./store/userStore";

// 滚动条配置
NProgress.configure({ showSpinner: false })

// 路由白名单
const whiteList = ['/login', '/404']

router.beforeEach(async (to, _from, next) => {
    // 开启滚动条
    NProgress.start()

    // 实例仓库
    const permissionStore = usePermissionStore()
    const userStore = useUserStore()
    
    // 1 判断是否有token
    const { token } = userStore
    if (token) {
        // 判断是否去login
        if (to.path === '/login') {
            // 不允许登陆状态切换用户,跳到首页
            next('/')
        } else {
            // 判断是否获取到了用户信息
            const { isGetUserInfo } = permissionStore
            // 如果有用户信息则放行
            if (isGetUserInfo) {
                // 放行
                next()
            } else {
                // 没有用户信息则尝试获取用户信息
                try {
                    await userStore.MyGetUserInfo()
                    // 获取用户信息成功后:
                    // 1 拿到角色
                    const { role } = userStore
                    // 2 传入角色,获取动态路由
                    const accessRoutes = await permissionStore.generateRoute(role as string)
                    // 3 遍历添加单个路由
                    accessRoutes.forEach(route => {
                        router.addRoute(route)
                    })
                    // 4 设置获取用户信息状态为true
                    permissionStore.setUserInfoState(true)
                    // hack方法,再跑一次
                    next({ ...to, replace: true })
                } catch (error) {
                    // 获取用户信息失败则重置信息且跳转到登陆页面
                    await userStore.ClearInfo()
                    next('/login')
                }
            }
        }
    } else {
        // 判断是否去白名单
        if (whiteList.includes(to.path)) {
            // 是则放行
            next()
        }
        // 不是则去登陆
        next(`/login?redirect=${to.fullPath}`)
    }
})
// 后置守卫,结束滚动条
router.afterEach(() => {
    NProgress.done()
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值