简介:教育分教师、学生角色的路由拦截、路由权限的处理;
流程:(
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 其他在需要的就根据其他自行添加或者修改