【vue项目权限控制方案】

ops/2025/2/2 4:48:53/

文章目录

  • 后端控制权限
  • 模拟后端接口
  • 前端请求逻辑
    • 登陆
  • 前端路由和按钮权限控制

后端控制权限

思路:用户登录后可以获取到用户登陆的菜单,在跳转到下一个页面前,将获取到的用户的菜单格式化一下,以满足前端的规则,然后通过addRoute方法把新的路由加进去,然后记录路由规则的state,方便后续使用。

模拟后端接口

前端请求/routers接口时传入的用户id,后端返回相应的(该用户有权限的)页面,返回数据大概如下:
请添加图片描述
前端访问/login接口传入账户密码,然后返回相应的id,代码大概如下:
请添加图片描述

前端请求逻辑

route/index里面的路由规则是基本的路由规则,是不用登录也能访问的页面。perssion.js里面的路由规则需要登录才能访问,需要根据权限来判断能不能访问

登陆

将用户输入的账号密码传给后端,使用js-cookie库的Cookies.set将后端返回的token保存在cookie中,views/login.vue:

<template><div class="home"><input v-model="username" /><input v-model="password" /><button @click="loginIn">登录</button></div>
</template><script>
import axios from "axios"
import Cookies from 'js-cookie'export default {name: 'login',data() {return {username: "",password: ""}},methods: {loginIn() {axios.post("http://localhost:3000/login",{ username: this.username, password: this.password }).then((res) => {if (res.data.token) {Cookies.set('token', res.data.token);Cookies.set('id', res.data.id);this.$router.push("/");}})}}
}
</script>  

建议将路由规则保存在store里,因为首页渲染菜单需要用到。
思路:在actions中发请求获取路由规则,然后解析并格式化路由规则,在mutation中修改路由。store/index.js:

import Vue from 'vue'
import Vuex from 'vuex'
import Cookies from 'js-cookie'
import { initRoutes, resetRouter } from "../router"
import axios from 'axios'
Vue.use(Vuex)export default new Vuex.Store({state: {asyncRoute: [],// 请求回来的路由routes: []// 所有的路由(初始路由+请求回来的路由)},mutations: {SET_ROUTES: (state, routes) => {state.asyncRoute = routes;state.routes = initRoutes.concat(routes);// 初始路由拼接请求回来的路由,获得完整路由},RESET_ROUTES: (state, routes) => {state.asyncRoute = [];state.routes = [];},},actions: {// 发请求获取路由规则,然后解析并格式化路由规则,返回出去供前端使用getRouter({ commit }) {// routeArr为路由规则数组,就是访问/routers得到的响应数组function parseRouter(routeArr) {let _newArr = [];routeArr.forEach((item) => {let _newItem = Object.assign({}, item);let _str = item.component;//"/page1.vue"=>import("@/views/page1.vue")//格式化规则_newItem.component = (resolve) => {//两个坑//return require([`@/views${_str}`],resolve)// 1. 有些低版本的webpack不能使用import,得用requirereturn import(`@/views${_str}`)// 2. 这里必须用模版引擎,并且后端返回不能返回src/views,如果带上了,这里写`@${_str}`也会报错}_newArr.push(_newItem);})return _newArr}let _id = Cookies.get("id")if (_id) {return new Promise((resolve, reject) => {// 每次刷新页面都会发请求,所以每次路由跳转前先检查localStorage中有没有路由规则,有则直接使用,没有再发请求获取,并将请求到的路由规则保存在localStorage中let _local = JSON.parse(localStorage.getItem("menu"));if (_local) {let _newArr = parseRouter(_local);commit("SET_ROUTES", _newArr);resolve(_newArr)} else {axios.get("http://localhost:3000/routes?id=" + _id).then((res) => {let _newArr = parseRouter(res.data.data)localStorage.setItem("menu", JSON.stringify(res.data.data));commit("SET_ROUTES", _newArr);resolve(_newArr);})}})}},//按钮//登录-拉去一下用户的权限code ["some1","SOMETHING"]getCode() {},resetRouter({ commit }) {resetRouter();commit('RESET_ROUTES');}},modules: {}
})

router/index.js:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import login from '../views/login.vue'
Vue.use(VueRouter)
export const initRoutes = [{path: '/',name: 'Home',component: Home,meta: {// 可以访问这个页面的用户,用户登陆后,前端可以通过登陆接口获取到用户,如果是admin/manger用户,在beforeEach中通过to.meta.whiteList判断当前用户有没有权限,// 如果有权限,to.next()whiteList: ["admin", "manger"]}},{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.component: function () {return import(/* webpackChunkName: "about" */ '../views/About.vue')}},{path: '/login',name: 'login',component: login},
]const router = new VueRouter({routes: initRoutes
})// 重置路由规则:创建新的路由,把新路由的规则给老路由
export function resetRouter() {const newrouter = new VueRouter({routes: initRoutes})router.matcher = newrouter.matcher
}
export default router

权限控制页面perssion.js

import router from './router'
import store from './store'
import axios from "axios"
import Cookies from 'js-cookie'
//根据id请求接口获取规则
let whiteList = ["/about", "/login"]// 不需要登陆就可以访问的页面
// 因为store.dispatch("getRouter")会返回一个promise,需要await一下,等返回后再操作,所以这里得写成async函数
router.beforeEach(async (to, from, next) => {const token = Cookies.get("token");if (token) {if (to.path == "/login") {next("/");} else {//判断是不是已经请求拿了路由规则了if (store.state.asyncRoute.length == 0) {const _asyncRoutes = await store.dispatch("getRouter");// 获取到路由规则_asyncRoutes.forEach((item) => {router.addRoute(item);//注册路由})//继续跳转next(to.path)} else {//没有page3 page4//user page1 page2 if (to.matched.length != 0) {// 要去的这个路由在路由规则中有没有匹配next();} else {alert("无页面权限")next(from.path);}}}} else {if (whiteList.indexOf(to.path) != -1) {next()} else {next("/login")}}
})

登陆页:

<template><div class="home"><input v-model="username" /><input v-model="password" /><button @click="loginIn">登录</button></div>
</template><script>
import axios from "axios"
import Cookies from 'js-cookie'export default {name: 'login',data() {return {username: "",password: ""}},methods: {loginIn() {axios.post("http://localhost:3000/login",{ username: this.username, password: this.password }).then((res) => {if (res.data.token) {Cookies.set('token', res.data.token);Cookies.set('id', res.data.id);this.$router.push("/");}})}}
}
</script>

登出页:

<template><div class="home"><div v-for="item in $store.state.routes"><router-link :to="item.path">{{ item.name }}</router-link></div><button @click="loginout">登出</button></div>
</template><script>
import Cookie from "js-cookie"
export default {name: 'home',created() {},methods: {loginout() {// 退出登陆时清空cookie,清空localStorage、store,清空路由,跳转到登陆页Cookie.remove("id");Cookie.remove("token");localStorage.removeItem("menu");this.$store.dispatch("resetRouter")this.$router.push("/login")}}
}
</script>

前端路由和按钮权限控制

按钮权限思路:登陆时拉取用户权限code,每个code都有对应的操作权限,如果按钮有某个操作权限,则展示,否则隐藏
路由思路:为路由定义meta属性,在其中定义whiteList对象,存放可以访问这个页面的用户,用户登陆后,前端可以通过登陆接口获取到用户,如果是admin/manger用户,在beforeEach中通过to.meta.whiteList判断当前用户有没有权限,如果有权限:to.next()

export const initRoutes = [{path: '/',name: 'Home',component: Home,meta: {// 可以访问这个页面的用户,用户登陆后,前端可以通过登陆接口获取到用户,如果是admin/manger用户,在beforeEach中通过to.meta.whiteList判断当前用户有没有权限,// 如果有权限,to.next()whiteList: ["admin", "manger"]}},]

http://www.ppmy.cn/ops/154943.html

相关文章

【实践】基于SakuraLLM的离线日文漫画及视频汉化

介绍 LLM 大型语言模型&#xff08;英语&#xff1a;large language model&#xff0c;LLM&#xff09;&#xff0c;也称大语言模型&#xff0c;是由具有大量参数&#xff08;通常数十亿个权重或更多&#xff09;的人工神经网络组成的一类语言模型。在进行语言理解与分析&…

AI大模型开发原理篇-4:神经概率语言模型NPLM

神经概率语言模型&#xff08;NPLM&#xff09;概述 神经概率语言模型&#xff08;Neural Probabilistic Language Model, NPLM&#xff09; 是一种基于神经网络的语言建模方法&#xff0c;它将传统的语言模型和神经网络结合在一起&#xff0c;能够更好地捕捉语言中的复杂规律…

SQL99之内连接查询

SQL99是SQL语言的一个标准&#xff0c;于1999年发布。内连接查询是SQL中非常常用的一种查询方式&#xff0c;用于根据指定的条件从两个或多个表中获取相关联的数据。下面将详细介绍SQL99中的内连接查询&#xff0c;并以通熟易懂的语言进行讲解&#xff0c;同时给出代码例子、注…

WordPress event-monster插件存在信息泄露漏洞(CVE-2024-11396)

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…

css 实现进度条和数字自增动画效果

示例 property 定义参数 /* 定义参数 */property --step {syntax: <integer>;inherits: true;initial-value: 10;}/* 添加动画 */keyframes widthAm {0% {width: 10%;--step: 10;}100% {width: 80%;--step: 80;}}counter-reset 定义css计数器 /* 定义css计数器 */counter…

Java基础知识总结(三十六)--IO流

用于处理设备上数据。在流中一般以字节的形式存放着数据&#xff01; 流&#xff1a;可以理解数据的流动&#xff0c;就是一个数据流。IO流最终要以对象来体现&#xff0c;对象都存在IO包中。 流也进行分类&#xff1a; 1&#xff1a;输入流&#xff08;读&#xff09;和输出…

关于bash内建echo输出多行文本

echo命令 使用下述命令可以判断当前使用的echo命令是内建命令还是外部命令 type echo有下述输出&#xff0c;说明是内建命令 bash的内建命令输出多行文本时会拆分多次写入 如果希望不拆分多次写入&#xff0c;可以借用tee工具 tee工具可以将命令的输出同时发送到终端和文件…

菜鸟之路Day08一一集合进阶(一)

菜鸟之路Day08一一集合进阶(一) 作者&#xff1a;blue 时间&#xff1a;2025.1.26 文章目录 菜鸟之路Day08一一集合进阶(一)1.五道经典算法题1.1自定义排序1.2不死神兔1.3猴子吃桃子1.4爬楼梯1.5爬楼梯plus 2.单列集合2.1单列集合体系结构2.2Collection2.2.1Collection的常用…