页面设计

权限管理设计

布局设置

image

accessEnum.ts

const ACCESS_ENUM = {
  NOT_LOGIN: "notLogin",
  USER: "user",
  ADMIN: "admin",
};

export default ACCESS_ENUM;

checkAccess.ts
这个用于检查权限,参数是传递过来跳转路由需要的权限
然后这里面获取登录用户的权限,两个对比

例如这个需要权限

{
    path: "/image",
    name: "图片展示",
    meta: {
      hidenInMenu: true,
    },
    component: ImageView,
  },

有的跳转不需要权限

 {
    path: "/",
    name: "首页",
    component: HomeView,
  },

用这个获取需要的权限

//存在就获取,不存在就是undefined
const needAccess = (to.meta?.access as string) ?? ACCESS_ENUM.NOT_LOGIN;

const needAccess:这是声明一个常量变量 needAccess。
to.meta?.access:这是 Vue Router 中路由导航守卫的一个特性。to 是即将跳转到的目标路由对象,meta 是路由元信息对象,?. 是可选链操作符,用于判断 to.meta 是否存在,如果存在,则继续访问 access 属性。
as string:这是 TypeScript 的类型断言,将 to.meta?.access 强制转换为字符串类型。这里假设 access 属性是一个字符串,但由于可选链操作符的使用,它可能为空。
?? ACCESS_ENUM.NOT_LOGIN:这是空值合并运算符 (nullish coalescing operator),用于判断 to.meta?.access as string 是否为 null 或 undefined,如果是,则返回 ACCESS_ENUM.NOT_LOGIN。空值合并运算符用于提供默认值,即如果 to.meta?.access 为空,则将 needAccess 赋值为 ACCESS_ENUM.NOT_LOGIN。
总的来说,这行代码的含义是:如果目标路由对象 to 的元信息中存在 access 属性,则将其转换为字符串并赋值给 needAccess 变量;如果不存在或为空,则将 needAccess 赋值为 ACCESS_ENUM.NOT_LOGIN。
/*
 * 检查权限(判断当前登录用户是否具有某个权限)
 *  logingUSER 当前登录用户
 * needAccess 需要有的权限
 * boolean 有无权限
 * */
import ACCESS_ENUM from "@/access/accessEnum";

/**
 * 检查权限(判断当前登录用户是否具有某个权限)
 * @param loginUser 当前登录用户
 * @param needAccess 需要有的权限
 * @return boolean 有无权限
 */
const checkAccess = (loginUser: any, needAccess = ACCESS_ENUM.NOT_LOGIN) => {
  // 获取当前登录用户具有的权限(如果没有 loginUser,则表示未登录),和这个路由跳转权限对比
  const loginUserAccess = loginUser?.userRole ?? ACCESS_ENUM.NOT_LOGIN;
  //这个权限是不需要登录的,直接返回
  if (needAccess === ACCESS_ENUM.NOT_LOGIN) {
    return true;
  }

  // 如果用户登录才能访问,这个是登录了,需要用户权限,但是登录的用户没有用户权限
  if (needAccess === ACCESS_ENUM.USER) {
    // 如果用户没登录,那么表示无权限,查看登录用户是否已经登录了
    //这个是登录用户的权限,需要的权限是user,但是登录用户的权限显示ACCESS_ENUM.NOT_LOGIN,返回跳转到无权限页面
    if (loginUserAccess === ACCESS_ENUM.NOT_LOGIN) {
      return false;
    }
  }
  // 如果需要管理员权限
  if (needAccess === ACCESS_ENUM.ADMIN) {
    // 如果不为管理员,表示无权限
    //需要管理员权限
    if (loginUserAccess !== ACCESS_ENUM.ADMIN) {
      return false;
    }
  }
  return true;
};

export default checkAccess;

indes.ts
这个是路由守卫,跳转路由触发,然后检查权限

import store from "@/store";
import ACCESS_ENUM from "@/access/accessEnum";
import checkAccess from "@/access/checkAccess";
import router from "@/router";

router.beforeEach(async (to, from, next) => {
  // alert("xxxx13" + "45");

  console.log("登录用户信息", store.state.user.loginUser);
  console.log(to.matched);

  const loginUser = store.state.user.loginUser;
  if (!loginUser || !loginUser.userRole) {
    //用来触发action方法
    await store.dispatch("user/getLoginUser");
  }

  //不需要登录就是ACCESS_ENUM.NOT_LOGIN,这个从meta取的
  const needAccess = (to.meta?.access as string) ?? ACCESS_ENUM.NOT_LOGIN;
  //要跳转的页面必须登录,需要判断权限
  if (needAccess !== ACCESS_ENUM.NOT_LOGIN) {
    //如果没有登录,跳转到登录页面
    //如果没有登录!loginUser就是ture
    if (!loginUser) {
      next(`/user/login?redirect=${to.fullPath}`);
      return;
    }

    //如果已经登录了,但是权限不足,那么跳转到无权限界面
    if (!checkAccess(loginUser, needAccess)) {
      next("/noAuth");
      return;
    }
    //仅管理员可见,判断当前用户是否有权限
    // if (to.meta?.access === "canAdmin") {
    //   if (store.state.user.loginUser?.role === "admin") {
    //     next("/noAuth");
    //     return;
    //   }
    // }
  }

  //不需要登录直接跳转
  next();
  console.log(to);
});

设计全局对象

image

index.ts

import { createStore } from "vuex";
import user from "./user";

export default createStore({
  mutations: {},
  actions: {},
  modules: {
    user,
  },
});

user.ts

import { StoreOptions } from "vuex";
import { UserControllerService } from "../../generated";
import ACCESS_ENUM from "@/access/accessEnum";

export default {
  namespaced: true,
  state: () => ({
    //存储用户信息,这里是存储一个对象信息
    loginUser: {
      userName: "未登录",
      role: "notLogin",
    },
  }),

  actions: {
    // getLoginUser({ commit, state }, payload) {
    //   commit("updateUser", { userName: "鱼皮" });
    // },
    //payload的作用
    async getLoginUser({ commit, state }, payload) {
      const res = await UserControllerService.getLoginUserUsingGet();
      // console.log("xxxxxxxxxxxxxxxxxxxx");
      console.log(res);
      if (res.code === 0) {
        commit("updateUser", res.data);
      } else {
        commit("updateUser", {
          ...state.loginUser,
          userRole: ACCESS_ENUM.NOT_LOGIN,
        });
      }
    },
  },

  mutations: {
    updateUser(state, payload) {
      console.log("payload");
      console.log(payload);
      state.loginUser = payload;
    },
  },
} as StoreOptions<any>;

路由

image

index.ts

import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import { routes } from "@/router/routes";

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});

export default router;

routes.ts

import { RouteRecordRaw } from "vue-router";
import HomeView from "@/views/HomeView.vue";
import NoAuth from "@/views/NoAuth.vue";
import AdminView from "@/views/AdminView.vue";
import ImageView from "@/views/ImageView.vue";
import UserLoginView from "@/views/user/UserLoginView.vue";
import UserRegisterView from "@/views/user/UserRegisterView.vue";

import AboutView from "@/views/AboutView.vue";
import UserLayout from "@/layouts/UserLayout.vue";

export const routes: Array<RouteRecordRaw> = [
  {
    path: "/user",
    name: "用户",
    component: UserLayout,
    children: [
      {
        path: "login",
        name: "用户登录",
        component: UserLoginView,
      },
      {
        path: "register",
        name: "用户注册",
        component: UserRegisterView,
      },
    ],
  },
  {
    path: "/",
    name: "首页",
    component: HomeView,
  },
  {
    path: "/noAuth",
    name: "无权限",
    component: NoAuth,
  },
  {
    path: "/image",
    name: "图片展示",
    meta: {
      hidenInMenu: true,
    },
    component: ImageView,
  },
  {
    path: "/admin",
    name: "管理员可见",
    component: AdminView,
    meta: {
      access: "canAdmin",
    },
  },
  {
    path: "/about",
    name: "about",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    meta: {
      hidenInMenu: true,
    },
    component: AboutView,
    // component: () =>
    //   import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
  },
];

posted @ 2024-02-16 10:23  拿受用  阅读(13)  评论(0编辑  收藏  举报