vue 权限模块(token,路由,按钮)

73 阅读3分钟

token权限思路描述

// 使用前置路由守卫 beforeEach(每次页面跳转前都会执行刷新也会)
// 在这里开启进度条
// 设置每个页面的标题
// 获取token
// 判断当前有无token,如果有token执行下面操作
login接口返回token,getInfo接口返回routes,name等信息
如果有name则放行,否则,发请求去拿用户信息
// 有过无token 有两种情况,一种是没有登录过,还有一种是token过期了,这两种情况都需要进行重新跳转登录页登录

token权限代码

import router from "./router";
import store from "./store";
import { Message } from "element-ui";
import NProgress from "nprogress"; // 水平进度条提示: 在跳转路由时使用
import "nprogress/nprogress.css"; // 水平进度条样式
import getPageTitle from "@/utils/get-page-title"; // 获取应用头部标题的函数
NProgress.configure({ showSpinner: false }); // 配置NProgress: 不显示右侧旋转进度条
// 不用进行token检查的白名单路径数组
const whiteList = ["/login"];
// 注册全局前置守卫: 在路由准备跳转前执行
router.beforeEach(async (to, from, next) => {
  // 在显示进度条
  NProgress.start();
  // 设置整个页面的标题
  document.title = getPageTitle(to.meta.title);
  // 获取cookie中保存的token
  const token = store.getters.token;
  // 如果token存在(已经登陆或前面登陆过)
  if (token) {
    // 如果请求的是登陆路由
    if (to.path === "/login") {
      // 直接跳转到根路由, 并完成进度条
      next({ path: "/" });
      NProgress.done();
    } else {
      // 请求的不是登陆路由
      // 是否已经登陆
      // 刚进来是没有用户名字的,因为login接口只反回了token
      const hasLogin = !!store.getters.name;
      // token没有过期,放行
      if (hasLogin) {
        next();
      } else {
        // 如果还没有获取用户信息
        try {
          // 异步请求获取用户信息(包含权限数据) ==> 动态注册用户权限路由 (有一个特点: 当次跳转路由不可见)
          await store.dispatch("user/getInfo");
          // 重新跳转去目标路由
          // next()  // 有问题   刷新会白屏  直接放行会看不到动态添加的异步路由
          // next(to.path) // 重新跳转去目标路由, 能看到动态添加的异步路由, 但会丢失参数
          next(to); // 重新跳转去目标路由, 能看到动态添加的异步路由, 且不会丢失参数
          NProgress.done(); // 结束进度条
          // to: {name, path, params, query, meta}
        } catch (error) {
          // 如果请求处理过程中出错
          // 重置用户信息
          await store.dispatch("user/resetUser");
          // 提示错误信息
          Message.error(error || "Has Error");
          // 跳转到登陆页面, 并携带原本要跳转的路由路径, 用于登陆成功后跳转
          next(`/login?redirect=${to.path}`);
          // 完成进度条
          NProgress.done();
        }
      }
    }
  } else {
    // 没有token(或者token过期了)
    // 如果目标路径在白名单中(是不需要token的路径)
    if (whiteList.indexOf(to.path) !== -1) {
      // 放行
      next();
    } else {
      // 如果没在白名单中, 跳转到登陆路由携带原目标路径
      next(`/login?redirect=${to.path}`);
      // 完成进度条  当次跳转中断了, 要进行一个新的跳转了
      NProgress.done();
    }
  }
});

// 注册全局后置守卫: 在路由跳转完成后执行
router.afterEach(() => {
  // console.log('afterEnter callback()')
  // 完成(隐藏)进度条显示
  NProgress.done();
});

路由权限

// 将路由分为三种
1.常量路由
包括登陆/404/首页
2./* 所有异步路由 */
3./* 匹配任意的路由 必须最后注册 */
// 做一个递归,在所以异步路由中取出用户有权限的路由
// 接着使用  // 将当前用户的异步权限路由和备选路由添加到路由器
    router.addRoutes([...asyncRoutes, anyRoute]);
//   // 合并常量路由,异步路由与备选路由, 并保存  

按钮权限

<template>
  <el-button v-bind="$attrs" v-if="userInfoStore.buttons.includes(permission)">
    <slot />
  </el-button>
</template>

<script lang="ts">
export default {
  name: "PermissionButton",
};
</script>

<script lang="ts" setup>
import { useUserInfoStore } from "@/stores/userInfo";

const userInfoStore = useUserInfoStore();

defineProps<{
  permission: string;
}>();
</script>

<style scoped></style>