前言

不管是移动端,还是pc端,可能都会有用户登录操作,不同的用户之间又拥有不同的角色,而不同角色之间势必存在不同的权限;
如果按照类型划分,大概可分为三类:菜单权限、按钮权限、数据权限;
数据权限:前端在请求头统一封装,携带用户信息,由后端解析返回;
菜单权限:通过element菜单组件实现;
按钮权限:通过自定义指令实现;
菜单权限&按钮权限:本质上也是通过数据权限,由后端返回当前用户所有有权限菜单及按钮,然后由前端处理;

login接口返回数据格式

登录接口按照类似格式返回是处理一切权限问题的前提;
内容主要包含用户信息,菜单信息,按钮信息等,其中:
token:用于前端请求头封装,后端根据此字段判断用户信息;
menus:当前登录用户菜单权限列表,用于菜单权限的处理;
permissions:当前登录用户按钮权限列表,用于按钮权限的处理;
具体数据结构如下:

{"code": 1,"data": {"id": "1237361915165020161","username": "admin","phone": "178****9154","nickName": "小d","realName": "段段","sex": 1,"deptId": "1237322421447561216","deptName": "测试部门","status": 1,"email": "1@qq.com","token":"token串", // 用于前端请求头封装,后端根据此字段判断用户信息"menus": [ // 当前登录用户菜单权限列表{"id": "1236916745927790564","title": "系统管理","icon": "el-icon-star-off","path": "/org","name": "org","children": [{"id": "1236916745927790578","title": "角色管理", "icon": "el-icon-s-promotion","path": "/roles","name": "roles","children": [],},{"id": "1236916745927790560","title": "菜单管理","icon": "el-icon-s-tools","path": "/menus","name": "menus","children": [],},{"id": "1236916745927790575","title": "用户管理","icon": "el-icon-s-custom","path": "/users","name": "user","children": [],}],"spread": true,"checked": false},{"id": "1236916745927790569","title": "账号管理","icon": "el-icon-s-data","path": "/user","name": "user","children": []}],"permissions": [ // 当前登录用户按钮权限"sys:log:delete","sys:user:add","sys:role:update","sys:dept:list"]}
}

数据权限

1.登录接口返回当前用户token

具体的返回形式如login返回数据;

2.login接口数据存储vuex

推荐文章:链接

3.接口请求二次封装

// 此为移动端配置,引用了vant组件,如要换成其他组件请修改配置
// import Vue from 'vue'
import axios from 'axios'
import qs from 'qs'
import { isEmpty, isFormData, filterObj } from '@/utils/function.js'
import { Toast, Dialog } from 'vant'let pending = [] // 声明一个数组用于存储每个ajax请求的取消函数和ajax标识
let CancelToken = axios.CancelTokenconst TIMEOUT = 3000
const baseURL = process.env.VUE_APP_BASE_UPLconst getErrorString = (errorObj, defaultStr = '') => {let errStr = defaultStr// 对象if (typeof errorObj === 'object') {if (errorObj.response && errorObj.response.status) {errStr = `${errorObj.response.status}-${errorObj.response.statusText}`} else if (errorObj.message && typeof errorObj.message === 'string') {errStr = `${errorObj.message} 无返回或非正常操作`}} else if (typeof errorObj === 'string') {errStr = errorObj}return errStr
}const removePending = ever => {for (const p in pending) {if (pending[p].u === ever.url + '&' + ever.method) {// 当当前请求在数组中存在时执行函数体pending[p].f() // 执行取消操作pending.splice(p, 1) // 把这条记录从数组中移除}}
}function handleResponse (response, options) {if (!response || !options) returnif (options.showLoading && options.data && !options.data.hideLoading) {Toast.clear()}if (response.status === 200) {const data = response.dataconst contentType = response.headers['content-type']if (data.code === '40001') {Dialog.alert({message: data.message || '内部错误'}).then(() => {})return}if (contentType && contentType.indexOf('json') !== -1) {if (response.data.constructor === window.Blob) {const reader = new FileReader()reader.readAsText(response.data)reader.addEventListener('loadend', function () {const res = JSON.parse(reader.result)Toast(`${response.data.message || '未知异常'}`)})} else {const data = eval(response.data)const { success, message } = dataif (!success && !options.noToast) {Toast(`${response.data.message || '未知异常'}`)}}}} else if (response.status === 401 && options.showLoading) {Toast(`${response.data.message || '未知异常'}`)} else if (response.status > 401) {Toast(`${response.data.message || '未知异常'}`)} else if (response.status === '504') {Toast('请求错误 网络异常')}
}
const fetch = options => {const {method = 'get',data,url,headers,config} = optionsconst { token } = store.state.login.userconst axiosConfig = {timeout: TIMEOUT,baseURL,withCredentials: true,headers: {...headers,'token': token // 重点:用户请求头的封装}}const instance = axios.create(axiosConfig)instance.interceptors.request.use(config => {// 判断是否需要显示满屏loading遮罩if (options.showLoading && options.data && !options.data.hideLoading) {Toast.loading({mask: true,loadingType: 'spinner',// message: '加载中...',duration: 30000,getContainer: '#app'})}removePending(config) // 在一个ajax发送前执行一下取消操作config.cancelToken = new CancelToken(c => {// 这里的ajax标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式pending.push({ u: config.url + '&' + config.method, f: c })})return config},err => {return Promise.reject(new Error(getErrorString(err, 'request错误')))})instance.interceptors.response.use(response => {try {handleResponse(response, options)// ------------------------------------------------------------------------------------------removePending(options.config) // 在一个ajax响应后再执行一下取消操作,把已经完成的请求从pending中移除// -------------------------------------------------------------------------------------------} catch (err) { }return response},err => {handleResponse(err.response, options)return Promise.reject(new Error(getErrorString(err, 'response错误')))})const filterData = isFormData ? data : filterObj(data)switch (method.toLowerCase()) {case 'get':return instance.get(`${url}${!isEmpty(data) ? `?${qs.stringify(data)}` : ''}`,config)case 'delete':return instance.delete(url, { data: filterData })case 'head':return instance.head(url, filterData)case 'post':return instance.post(url, filterData, config)case 'put':return instance.put(url, filterData, config)case 'patch':return instance.patch(url, filterData)default:return instance(options)}
}export default function request (options) {return new Promise((resolve, reject) => {fetch(options).then(response => {resolve(response.data)}).catch(err => {reject(err)})})
}

查看封装是否成功

至此,封装完结;请求头中插入token信息,后端根据token进行用户解析,从而达到数据权限的处理;

菜单权限

1.登录接口返回当前用户权限菜单

具体的返回形式如login返回数据;

2.login接口数据存储vuex

推荐文章:链接

3.element的menu组件渲染菜单

按钮权限

1.登录接口返回当前用户按钮菜单

具体的返回形式如login返回数据;

2.login接口数据存储vuex

推荐文章:链接

3.自定义指令处理权限菜单

新建directives文件夹-----index.js文件
import directives from './permission'
export default {install(Vue, options) {Vue.directive('has',directives);}
}
新建directives文件夹-----permission.js文件
import store from '@/store'
export default {inserted:(el,binding,vnode) => {let { userInfo = {} } = store.getterslet {permissions = []} = userInfopermissions && !permissions.some(item => item==binding.value)&&(el.parentNode.removeChild(el));}
}
按钮权限增加
// 示例如下
<el-button v-has='sys:log:delete' type="primary" round>主要按钮</el-button>

vue项目权限:数据权限、菜单权限、按钮权限相关推荐

  1. vue项目-element UI-NavMenu 导航菜单始终只展开一个

    vue项目-element UI-NavMenu 导航菜单始终只展开一个 全局搜索:unique-opened找到该配置将其改成true unique-opened:是否只保持一个子菜单的展开 < ...

  2. Vue 进阶系列丨自定义指令实现按钮权限功能

    Vue 进阶系列教程将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的.若感本文对您有所帮助请点个赞吧! 2013年7月28日,尤雨溪第一次 ...

  3. vue项目-点击添加或者修改按钮浏览器的屏幕变黑,再次点击屏幕之后浏览器恢复正常(火狐浏览器、ChromeCoreLauncher双核浏览器)

    今天在写springboot+vue项目的时候发现了一个bug,之前写的项目就没有这种情况,bug如下: 点击添加或者修改按钮浏览器的屏幕变黑,再次点击屏幕之后浏览器恢复正常 点击修改按钮 屏幕变黑 ...

  4. VUE项目实践1:设置编辑按钮,可保存,双向绑定

    VUE项目实践:设置编辑按钮,可保存,双向绑定 目录结构: 实现效果: 所有代码: 实现页面:ipobtion.vue 引用页面:index.vue 目录结构: ​​​​​​ ​​ 实现效果: ​​​ ...

  5. vue项目 mock数据

    一.mock文件 1.安装mock开发环境 npm i mockjs -D 2.在src目录下新建mock目录,结构如下: 3.json数据格式,即userInfo.json内容如下: {" ...

  6. Django Vue实现动态菜单、动态权限

    随着前后端分离架构的流行,在 web 应用中,RESTful API 几乎已经成为了开发者主要选择,它使得客户端和服务端不需要保存对方的详细信息,也就是无状态性,但是这样在项目中需要动态菜单和动态权限 ...

  7. 菜单权限及按钮权限控制

    实现思路: 1.通过利用动态路由.静态路由实现动态路由 2.通过router-beforeEach钩子监听是否有权限 3.利用Vue.directive监听页面挂在完成控制按钮权限 实现代码: rou ...

  8. vue 前端配置按钮权限

    拿到产品需要配置的按钮权限清单,如下 在中台 资源管理 配置中,根据页面位置添加,'权限标识'名称不可重复 注意一定要是菜单类型按钮,然后在"权限管理"通过勾选赋予按钮权限 登录后 ...

  9. 数据级的权限管理和功能级的权限管理的区别,不使用框架(shiro,springsecurity)做权限设计的思考

    1 数据级的权限管理和功能级的权限管理 引自:http://www.iteye.com/problems/97374 功能级权限,有大有小.大的可以直接包括一个业务模块,小的可以是一个按钮.一般的功能 ...

  10. 管理台权限模块 - 完整路由权限及按钮权限

    这篇文章主要讲的是动态路由添加,下篇我们再仔细说明一下按钮权限的做法, 本文基础框架在element-ui 及element-admin-template基础上进行的二次开发 动态路由权限: 首先这里 ...

最新文章

  1. 皮一皮:20岁和30岁的你的区别...
  2. 箱形图适用于哪种数据_盘点 | 十分钟进阶Excel数据可视化
  3. Android自定义控件_View的绘制流程
  4. Git的基础知识和常用命令
  5. .net runtime占用cpu_.net 中的StringBuilder和TextWriter区别
  6. java 6 update 3_Java(TM) 6 Update(java运行环境) V 6.0.450.6 官方版
  7. xmanager linux,教您用xmanager启动Linux上的图形界面程序-Go语言中文社区
  8. Go语言基础之10--面向对象编程2之方法
  9. nginx -- 负载均衡
  10. openssl代码领读目录
  11. 基于Matlab的LSTM神经网络时序预测(完整代码+范例数据文件)
  12. 微软「警告」员工不要在愚人节搞事情,为什么?
  13. C语言: “老板,来两份外卖,一份卤肉饭(%d),一份鸡汤面(%f)...“
  14. ajax提交表单序列化不进请求,表单序列化+ajax跨域提交
  15. 【Python例】利用 python 进行用户画像词云图的生成 --- wordcloud
  16. ZooKeeper报错:Unable to access datadir, exiting abnormally windows版本
  17. 巴贝奇——现代计算机真正的鼻祖
  18. OpenGL图形旋转
  19. 对象转二进制--》二进制转对象
  20. da0809 c语言程序,ADC0809做AD转换和DA转换的C程序.doc

热门文章

  1. executors与threadPoolExecutor区别
  2. Java爬虫实践:Jsoup+HttpUnit爬取今日头条、网易、搜狐、凤凰新闻
  3. 【Linux】安装虚拟机
  4. java 递归求 数字分解
  5. 复数基础——复数的基本运算_2
  6. 哈希算法(Hash函数)简单介绍
  7. raw图的存储格式和读取方式
  8. Facenet 原理介绍
  9. 生物信息学之抗癌药物反应论文阅读四:MD-WDNN
  10. 用C语言打印简单图案(爱心\圆形\三角形等)