vue3使用 pinia+权限管理+角色管理+路由拦截

简介:教育分教师、学生角色的路由拦截、路由权限的处理;

流程:(

1.登录拿到用户角色 

2.存储用户角色到 store中

3.需要配置的文件 3 个: permissions.ts \ router/index.ts \ main.ts

--------------------------------

 先 配置 三个文件: permissions.ts 文件

import type { RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
import { useUserStore } from './user';
import { msg } from "@/utils/utils"

// 是否拥有访问特定路由所需角色  用户角色必须包含所有需要的角色之一。
export function hasRoles(userRoles: string[], requiredRoles: string[]): boolean {
    //如果路由没有配置角色,那么可以直接访问
    if (requiredRoles == undefined || requiredRoles.length == 0) {
        return true
    }
    //如果用户没有角色,则不能访问所有路由 
    if (userRoles.length == 0) {
        return false
    }
    return requiredRoles.some(role => userRoles.includes(role));
}
// 验证用户是否具备所有必要的权限,以访问特定路由。
export function hasPermissions(userPermissions: string[], requiredPermissions: string[]): boolean {
    return requiredPermissions.every(permission => userPermissions.includes(permission));
}
/**
 * 获取用户的角色信息
 * @param userStore 登录的用户信息
 * @returns 
 */
// 从用户 store 中获取当前用户的 角色 列表。
export function getUserRoles(userStore): string[] {
    return userStore.getRoles()
}

/**
 *  获取用户的权限信息
 * @param userStore 登录的用户信息
 */
// 从用户 store 中获取当前用户的 权限 列表。
export function getUserPermissions(userStore): string[] {
    return userStore.getUser().permissions
}

/**
 * 是否登录
 * @param userStore 登录的用户信息
 * @returns 
 */
export function isLoggedIn(userStore) {
    return userStore.getUser().id != "" ? true : false
}
// 如果目标路由是登录页(/Login),直接放行。
// 如果用户未登录,重定向到登录页。
// 如果路由需要权限,但用户角色不匹配,重定向到无权限页面(/NoPermission)。
// 否则,允许访问路由。
export function routeGuard(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext): void {
    //用户
    const userStore = useUserStore()
    const userRoles = getUserRoles(userStore); // 获取用户的角色信息  
    if (to.path === '/Login') {
        next();
        return;
    }
    if (!isLoggedIn(userStore)) {
        next('/Login')
        console.log('走了没有登录用户信息的 --login');
    } else if (to.path === '/NoPermission') {
        console.log('----走了没有权限的---这里');
        next();
        return;
    } else if (!hasRoles(userRoles, to.meta.requiredRoles)) {
        console.log('----走了 用户角色不匹配的');
        // 如果需要特定角色但用户角色不匹配,则跳转到 403 页面
        // router.push({ name: 'Forbidden' });
        // next('/login')
        msg({ message: '当前角色不可访问,请切换角色', type: 'warning' })
    } else {
        // 其他情况下,允许访问路由
        next();
    }
}

main.ts 文件

import App from '@/App.vue';
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import 'animate.css';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import i18n from './locales';
import router from "@/router";
import store from "@/store/index"
import "@/styles/base/Tailwind.css"
import "@/styles/base/base.css"

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'virtual:svg-icons-register';
import SvgIcon from '@/components/SvgIcon.vue'
import { Swipe, SwipeItem } from 'vant';

const pinia = createPinia();
const app = createApp(App);
app.use(router);
app.use(store);
app.use(i18n);
app.use(ElementPlus);
app.use(pinia);
app.mount('#app');
app.component('SvgIcon', SvgIcon);
app.use(Swipe);
app.use(SwipeItem);
pinia.use(piniaPluginPersistedstate) 

router/index.ts 文件

import { createRouter, createWebHistory } from 'vue-router';
import { routeGuard } from "../store/user/permissions.ts"
//   路由文件
const LAYOUT = () => import("@/views/layout/index.vue");
const routes = [
  {
    path: '/',
    name: '寻师',
    redirect: '/index',
    children: [
      {
        path: '/index',
        name: 'Index',
        component: () => import('@/views/home/index.vue'),
      },
    ]
  },
  {
    path: '/tea',
    name: '教师中心',
    component: LAYOUT,
    meta: {
      requireAuth: true,
      requiredRoles: ['tea']
    },
    children: [
      {
        path: 'curse', //  课程管理
        name: '课程管理',
        component: () => import('@/views/teacher/curseManage.vue'),
        meta: {
          requireAuth: true,
          requiredRoles: ['tea']
        },
      },]
  },
  {
    path: '/stu', // 学生部分
    name: '',
    component: LAYOUT,
    meta: {
      requireAuth: true,
      requiredRoles: ['tea',]
    },
    children: [
      {
        path: 'curse', //  我的课程
        name: '我的课程',
        component: () => import('@/views/stu/center/myCurse.vue'),
        meta: {
          requireAuth: true,
          requiredRoles: ['stu']
        },
      },]
  },
  {
    path: '/user', // 公共部分
    name: '',
    component: LAYOUT,
    meta: {
      requireAuth: true, // 需要登录验证 两个角色 一个 user 学生 一个 teacher 'user'
      requiredRoles: ['tea', 'stu']
    },
    children: [
      {
        path: 'password',
        name: '密码',
        component: () => import('@/views/stu/account/password.vue')
      },
    ],
  },
]
// 创建路由实例
const router = createRouter({
  history: createWebHistory(),
  routes,
});
// 应用路由守卫
router.beforeEach(routeGuard);
export default router;
// 路由多语言 实现 先不删
// const router = createRouter({
//     history: createWebHistory(),
//     routes: [
//         { path: '/', component: Home }, // 默认英文版本
//         { path: '/zh-cn/', component: HomeZhCN }, // 简体中文版本
//         { path: '/zh-tc/', component: HomeZhTC }, // 繁体中文版本
//         { path: '/ru-ru/', component: HomeRuRU }, // 俄语版本
//     ]
// });

流程:

1. 登录拿到用户角色 进行本地存储  (本项目后端返回 roleid 1 2 我这里进行转化) 本地状态存储见 user.ts 文件

 userStore.setUser(res);
  localStorage.setItem("token", res?.token);
  const { role_id } = userStore.getUser();
  if (role_id === 1) {
    userStore.setRoles("stu");
  } else if (role_id === 2) {
    userStore.setRoles("tea");
  }

 user.ts (角色、token等基础信息存储) 使用等 

import { defineStore } from 'pinia'
import type { UserInfo } from './type'

export const useUserStore = defineStore('user', {
    state: () => ({
        user: {
            audit_overrule_instructions: '',
            avatar: '',
            email: '',
            is_set_password: 0,
            name: "",
            phone: "",
            role_id: 0,
            teacher_information_status: 0,
            token: "",
            uid: '',
        },
        roleType: {
            roles: '',
            permissions: []
        },
    }),
    persist: true,
    actions: {
        setUser(user: UserInfo) {
            this.user = user;
        },
        setRoles(role: role) {
            this.roleType.roles = role;
        },
        getUser() {
            return this.user;
        },
        getRoles() {
            return this.roleType.roles;
        },
        clearUser() {
            this.user.avatar = '';
            this.user.is_set_password = 0;
            this.user.name = '';
            this.user.phone = '';
            this.user.role_id = 0;
            this.user.teacher_information_status = 0;
            this.user.token = '';
            this.user.uid = '';
            this.user.email = '';
        }
    }
});
export const usePublic = defineStore('public', {
    state: () => ({
        areaList: []

    }),
    persist: true,
    actions: {
        setPublic(publicList: any) {
            this.areaList = publicList;
        },
        getPublic() {
            return this.areaList;
        },
        clearUser() {
            this.areaList = [];
        }
    }
}); 

至此 路由跳转拦截 根据角色 跳转拦截 地址 就 ok 其他在需要的就根据其他自行添加或者修改

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值