基于Vue的前端权限管理
前端涉及到的权限管理部分
·
前端权限控制的思路主要分为以下几个方向:👇👇👇👇👇
1.菜单的控制(导航侧边栏)
登录请求中得到后端返回的权限数据,前端根据权限数据动态展示对应菜单,点击菜单才能查看对应界面
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
user: JSON.parse(localStorage.getItem('user') || '[]'
},
mutations: {
setUser(state, user) {
state.user = user
// console.log(state.user);
localStorage.setItem('user', JSON.stringify(user))
}
},
actions: {
},
modules: {
}
})
Aside.vue
<template>
<div class="aside">
<el-menu
background-color="#00BFFF"
text-color="#fff"
>
<el-submenu v-for="(item,index) in this.menuList " :key="index" class="nav-title" :index="String(index)">
<template slot="title">
<i class="el-icon-location"></i>
<span slot="title">{{item.authName}}</span>
</template>
<el-menu-item v-for="(item,index) in item.children" :key="index" @click="$router.push({ path: item.path, query: { name: item.authName}})">{{item.authName}}</el-menu-item>
</el-submenu>
</el-menu>
</div>
</template>
<script>
// 菜单权限控制:login登录拿到权限数据,缓存到Vuex
// 从vuex中取值,赋给当前menulist,对menulist进行v-for遍历展示数据
import {mapState} from 'vuex';
export default {
data(){
return{
menuList:[]
}
},
methods:{},
mounted(){
this.menuList = this.user.rights
console.log(this.menuList,'菜单权限数据');
},
computed:{
...mapState(['user'])
}
}
</script>
<style lang="less" scoped>
.nav-title {
& /deep/ i {
color: #fff;
}
.el-menu-item {
color: #fff;
}
}
</style>
2.界面的控制
用户没有登录,手动在地址栏敲入地址,需要跳转到login界面;
动态路由。根据权限动态添加当前用户的路由;
用户已经登录,手动敲入权限外的地址,跳转404
router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
import NotFound from '../views/NotFound.vue'
import store from '../store/index'
Vue.use(VueRouter)
const routerOne = {
path: '/menu/one',
component: () => import('@/views/Page1.vue')
}
const routerTwo = {
path: '/menu/two',
component: () => import('@/views/Page1.vue')
}
const routerThree = {
path: '/menu/three',
component: () => import('@/views/Page1.vue')
}
const routerFour = {
path: '/menu/four',
component: () => import('@/views/Page1.vue')
}
const routerFive = {
path: '/menu/five',
component: () => import('@/views/Page1.vue')
}
const roleMap = {
"/menu/one": routerOne,
"/menu/two": routerTwo,
"/menu/three": routerThree,
"/menu/four": routerFour,
"/menu/five": routerFive,
}
const routes = [
{
path: '/',
name: 'Home',
component: Home,
redirect: '/menu/one',
children: []
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '*',
name: 'NotFound',
component: NotFound
}
]
const router = new VueRouter({
routes
})
// 路由导航守卫,对非法跳转手段进行拦截
router.beforeEach((to, from, next) => {
// console.log(from);
// console.log(to);
if (to.path === '/login') {
next();
} else {
const token = localStorage.getItem('token');
if (!token) {
next('/login');
} else {
next();
}
}
})
//动态路由,登录成功后根据二级路由权限进行路由匹配动态添加
export function initDynamicRoutes() {
// 对路由规则进行动态添加
console.log(router, '路由信息');
const currentRoutes = router.options.routes
let rights = store.state.user.rights;
console.log(rights, '用户路由权限');
rights.forEach(item => {
// console.log(item,'一级权限菜单');
// 当前用户的路由权限对应的路径进行映射对应的路由规则,push到当前路由children中
item.children.forEach(item => {
const temp = roleMap[item.path]
// 根据login的权限数据,给当前路由添加meta为对应权限的源数据
temp.meta = item.rights
currentRoutes[0].children.push(temp)
})
})
router.addRoutes(currentRoutes)
}
export default router
3.按钮的控制
在某个菜单的界面中,根据权限数据进行可操作按钮的展示,比如增删改查
permission.js
import Vue from "vue";
// 根据login的权限数据,给当前路由添加meta为对应权限的源数据,
// 使用自定义指令写一个action来判断当前用户对于这个按钮拥有的权限,如果login权限数据没有找到自定义指令的action,则代表没有权限
// 没有权限就进行禁用、删除的操作
import router from '../router/index'
Vue.directive('permission', {
inserted(el, binding) {
// console.log(el, '获取当前元素');
// console.log(binding, '当前元素后的内容');
// action:手动插入当前用户拥有的权限
const action = binding.value.action
const effect = binding.value.effect
// 判断当前路由对应的组件当中,当前用户拥有的权限
console.log(router.currentRoute);
const meta = router.currentRoute.meta
// console.log(meta, '当前路由下组件对应的用户权限');
// 手写的和后端权限数据进行条件判断,找不到代表没有权限,进行相关操作
if (meta.indexOf(action) == -1) {
if (effect === 'disabled') {
el.disabled = true
el.classList.add('is-disabled')
} else {
el.parentNode.removeChild(el)
}
}
}
})
<el-button
type="primary"
v-permission="{ action: 'add', effect: 'disabled' }"
@click="$emit('show')"
>添加商品</el-button
>
<!-- v-permission自定义指令控制按钮权限 -->
4.请求和响应的控制
用户通过非常规操作将按钮的禁用状态变为可用状态,请求应该被拦截
http.js
import axios from 'axios'
import Vue from "vue";
import router from '../router/index';
Vue.prototype.$http = axios
// 请求方式和权限的映射
const actionMap = {
"get": "view",
"post": "add",
"put": "edit",
"delete": "delete"
}
axios.interceptors.request.use((req) => {
// console.log(req.url,'请求路径');
// console.log(req.method,'请求方法');
if (req.url !== '/login') {
// 对非登录页的请求,都要添加token
req.headers.Authorization = localStorage.getItem('token')
// 根据请求得到是哪种操作
const action = actionMap[req.method]
// 对非权限范围内的请求要进行阻止
// 判断当前路由对应的权限
// 判断当前操作在组件的路由规则中是否存在
const currentRight = router.currentRoute.meta
if(currentRight && currentRight.indexOf(action) === -1){
alert('没有权限!')
return Promise.reject(new Error('没有权限!!'))
}
// 判断当前请求的行为
// restful请求风格(映射对应)
// get请求 view
// post请求 add
// put请求 edit
// delete请求 delete
}
return req
})
// axios.interceptors.response.use((res)=>{
// if(res.data.status === 401){
// router.push('/login')
// localStorage.clear()
// window.location.reload()
// }
// return res
// })
小结
前端权限的实现必须后端提供数据支持,否则无法实现,数据结构需要前后端沟通协商
菜单控制
1.登录请求返回的权限数据需要多组件共享,因此用vuex
2.防止刷新界面数据丢失,需要采用localstorage持久化,并且要setitem getitem使数据同步
界面控制
1.路由导航守卫,防止跳过登录界面
2.动态路由 addRoutes() ,路由路径和组件映射的方法,让不具备权限的界面的路由规则压根不存在
按钮控制
1.路由规则中增加meta元数据存储路由规则当前用户的权限
2.通过路由对象获得当前路由规则和其中的meta权限元数据
3.自定义指令控制按钮是否删除、禁用
请求和响应控制
1.请求拦截器和响应拦截器的使用
2.restful请求方法映射,先了解一下restful请求
更多推荐
已为社区贡献2条内容
所有评论(0)