Vue权限控制

您所在的位置:网站首页 生者与死者作者是谁 Vue权限控制

Vue权限控制

#Vue权限控制| 来源: 网络整理| 查看: 265

Vue权限控制 1.权限相关概念 1.1 权限的分类

后端权限

从根本上来讲,前端仅仅是视图层的战事,权限的核心在于服务器中数据的变化,所以后端才是权限的关键。

后端权限可以控制某个用户是否能够查询数据,是否能够修改数据库的操作。

后端如何知道请求是哪个用户发过来的

cookie session token 复制代码

后端的权限设计RBAC

用户 角色 权限 复制代码

前端权限

前端权限的控制,本质上来说就是控制前端的视图层的展示和前端所发送的请求,但是只有去前端权限控制没有后端权限控制,是万万不可以的。前端权限控制只是锦上添花的效果。

1.2 前端权限的意义

如果金葱能够修改服务器数据库中的数据层面来讲,确实只在后端控制就足够了,那为什么越来越多的翔宇也进行了前端权限的控制,主要有几个方面:

2.前端权限控制思路 2.1菜单的控制

在登录和请求中,会得到权限数据,当然这个需要后端数据的支持。前端根据权限数据,展示对应的菜单,点击菜单,才能查看相关的界面。

2.2 界面的控制

如果用户没有登录,手动在地址栏中敲入管理界面的地址,则需要跳转到登录界面

如果用户已经登录,可是手动敲入非权限内的地址,则需要跳转到404界面

2.3 按钮的控制

在某个菜单的界面中,还得根据权限数据,展示可以进行操作的按钮,比如删除、修改和增加

2.4 请求和响应的控制

如果用户通过非常规操作,比如通过浏览器调试工具,将某些禁用按钮变成启用状态,此时发送的请求,也应该被前端所拦截。

3.Vue的权限控制实现 3.1菜单控制

登录之后获取到的数据

{ "meta": { "status": 200 }, "data": { "id": "350000199209068278", "rid": 50, "username": "admin", "mobile": "@mobile()", "email": "[email protected]", "token": "#[[%#&@&[)*#^[[$&(&^]!%^#[]![@[)(([#%%%$]$((&%^[[", "avatar": "http://dummyimage.com/20×20/red/fff&text=avatar" }, "rights": [ { "id": 125, "authName": "用户管理", "icon": "el-icon-user-solid", "children": [ { "id": 110, "authName": "用户列表", "path": "users", "rights": [ "view", "edit", "add", "delete" ] } ] }, { "id": 103, "authName": "角色管理", "icon": "el-icon-setting", "children": [ { "id": 111, "authName": "角色列表", "path": "roles", "rights": [ "view", "edit", "add", "delete" ] } ] }, { "id": 101, "authName": "商品管理", "icon": "el-icon-chat-line-square", "children": [ { "id": 1001, "authName": "商品列表", "path": "goods", "rights": [ "view", "edit", "add", "delete" ] }, { "id": 1002, "authName": "商品分类", "path": "categories", "rights": [ "view", "edit", "add", "delete" ] } ] } ] } 复制代码

刷新界面菜单消失

原因分析

因为菜单数据是登录之后才获取到的,获取菜单数据之后,就存放在vuex中 一旦刷新界面,Vuex中的数据会重新初始化,所以会变成空的数组 因此,需要将权限数据存储在sessionStorage中,并让其和vuex中的数据保持同步 复制代码

代码解决

/store/index.js

import Vue from "vue"; import Vuex from "vuex"; import persist from "vuex-persistedstate"; Vue.use(Vuex); export default new Vuex.Store({ state: { rightList: JSON.parse(sessionStorage.getItem("rightList") || "[]"), username: "", }, getters: {}, mutations: { setRightList(state, data) { state.rightList = data; }, setUsername(state, data) { state.username = data; }, setToken(state, data) { state.token = data; }, }, actions: {}, modules: {}, plugins: [persist()], }); 复制代码 3.2界面控制

1670819796598

1.正常的逻辑是通过登录界面,登录成功之后跳转到管理平台界面,但是如果用户直接敲入管理平台的地址,也是可以跳过登录的步骤,所以应该在某个时机判断用户是否登录。

如何判断是否登录

什么时机

路由导航守卫

/router/index.js

router.beforeEach((to, from, next) => { if (to.path == "/login") { next(); } else { let { token } = JSON.parse(localStorage.getItem("vuex") || "[]"); if (!token) { next("/login"); } else { next(); } } }); 复制代码

2.虽然菜单项目已经被控制住了,但是路由信息还是完成存在于浏览器,比如zhangsan这个用户并不具备管理商品和商品分类的权限,但是如果他自己在地址栏中敲入/goods 或者 /roles的地址,依然可以访问角色界面。

路由导航守卫

动态路由

登录成功之后动态添加

App.vue中添加

import { initDynamicRoutes } from "./router"; export default { name: "app", created() { initDynamicRoutes(); }, }; 复制代码

/router.js

import Vue from "vue"; import VueRouter from "vue-router"; import Login from "../views/Login.vue"; import Home from "../views/Home.vue"; import Welcome from "../views/Welcome.vue"; import Users from "../views/Users.vue"; import Roles from "../views/Roles.vue"; import GoodsList from "../views/GoodsList.vue"; import GoodsCate from "../views/GoodsCate.vue"; import NotFound from "../views/NotFound.vue"; import store from "@/store"; Vue.use(VueRouter); //动态添加路由 const userRule = { path: "/users", component: Users }; const roleRule = { path: "/roles", component: Roles }; const goodRule = { path: "/goods", component: GoodsList }; const categoryRule = { path: "/categories", component: GoodsCate }; const ruleMapping = { users: userRule, roles: roleRule, goods: goodRule, categories: categoryRule, }; const routes = [ { path: "/", redirect: "/home", }, { path: "/login", component: Login, }, { path: "/home", component: Home, redirect: "/welcome", children: [ { path: "/welcome", component: Welcome }, // { path: "/users", component: Users }, // { path: "/roles", component: Roles }, // { path: "/goods", component: GoodsList }, // { path: "/categories", component: GoodsCate }, ], }, { path: "*", component: NotFound, }, ]; const router = new VueRouter({ mode: "history", base: process.env.BASE_URL, routes, }); router.beforeEach((to, from, next) => { if (to.path == "/login") { next(); } else { let { token } = JSON.parse(localStorage.getItem("vuex") || "[]"); if (!token) { next("/login"); } else { next(); } } }); //动态修改路由 export function initDynamicRoutes() { const currentRoutes = router.options.routes; const rightList = store.state.rightList; rightList.forEach((item) => { item.children.forEach((item) => { const temp = ruleMapping[item.path]; temp.meta = item.rights; currentRoutes[2].children.push(temp); }); }); router.addRoutes(currentRoutes); } export default router; 复制代码 3.3按钮控制

效果图

1670819692594

通过自定义指令,给button添加自定义指令v-permission,控制按钮的可用和不可用。

admin拥有管理用户的所有权限,包括对用户的增删改查 zhangsan只拥有查看用户的权限,不能增、删、改 复制代码

在入口文件中引入自定义指令

/main.js

import "./utils/permission.js"; 复制代码

添加自定义指令v-permission。如果

/utils/permission.js

import Vue from "vue"; import router from "@/router"; Vue.directive("permission", { inserted: function (el, binding) { const action = binding.value.action; const currentRight = router.currentRoute.meta; if (currentRight) { if (currentRight.indexOf(action) == -1) { const type = binding.value.effect; if (type === "disabled") { el.disabled = true; el.classList.add("is-disabled"); } else { el.parentElement.removeChild(el); } } } }, }); 复制代码

在用户列表中使用自定义组件

/views/Users.vue

查看 编辑 删除 复制代码 3.4请求控制

除了登录请求都得带上token,这样服务器才能鉴别你的身份

/utils/axios.js

axios.interceptors.request.use(function (req) { const currentUrl = req.url; if (currentUrl !== "login") { let { token } = JSON.parse(localStorage.getItem("vuex")); req.headers.Authorization = token; } 复制代码

如果发出了非权限内的请求,应该直接在前端访问内组织,虽然这个请求发送到服务器也会被拒绝

import Vue from "vue"; import axios from "axios"; import router from "@/router"; const actionMapping = { get: "view", post: "add", put: "edit", delete: "delete", }; axios.interceptors.request.use(function (req) { const currentUrl = req.url; if (currentUrl !== "login") { let { token } = JSON.parse(localStorage.getItem("vuex")); req.headers.Authorization = token; } /** * get请求 查看 * post请求 增加 * put请求 修改 * delete请求 删除 */ const method = req.method; const action = actionMapping[method]; const rights = router.currentRoute.meta; if (rights && rights.indexOf(action) == -1) { this.$message.warn("没有权限"); } return req; }); axios.interceptors.response.use(function (res) { return res; }); Vue.prototype.$axios = axios; 复制代码

响应控制

得到了服务器返回状态码401,代表token超时或者被篡改了,这时候应该强制跳转到登录界面

axios.interceptors.response.use(function (res) { if (res.data.meta.status === 401) { router.push("/login"); sessionStorage.clear(); window.location.reload(); } return res; }); 复制代码 4.小结

前端权限的控制必须要后端提供数据支持,否则无法实现

返回的权限数据的结构,前后端需要沟通协商,怎样的数据使用起来才最方便

4.1菜单控制 权限的数据需要多组件之间共享,因此采用vuex 防止刷新界面,权限数据丢失,所以需要存储在sessionStorage,并且要保证两者的同步 4.2界面控制 路由的导航守卫可以防止跳过登录界面 动态路由可以让不具备权限的界面的路由规则压根就不存在 4.3按钮控制 路由规则中可以增加路由元数据meta 通过路由对象可以得到当前的路由规则,以及存储在此规则中的meta数据 自定义指令可以很方便的实现按钮控制 4.4请求和响应控制 请求拦截器和响应拦截器的使用 请求方式的约定restfull


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3