前端权限控制的思路主要分为以下几个方向:👇👇👇👇👇


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请求

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐