美文网首页
Vue后台管理系统权限控制与管理

Vue后台管理系统权限控制与管理

作者: 前端小码农呀 | 来源:发表于2020-09-23 22:49 被阅读0次

    权限相关的概念

    某个用户是否有对某个数据的增删改查等操作的权限

    后端权限(对数据库中的数据的控制)

    1.权限的核心在于服务器中数据的变化,后端权限可以控制某个用户是否可以对数据进行增删改查的操作
    后端如何知道请求是哪个用户发送的??
    状态保持:

    cookie,session,token
    

    一般而言前后端分离开发采用token来鉴权
    2.后端权限设计RBAC(基于角色的权限控制)
    用户==>角色==>权限

    前端权限(视觉层面的控制)

    主要用来控制前端视图层的展示与前端所发送的请求
    意义:
    - 降低非法操作的可能性
    - 排除不必要的请求,减轻服务器的压力
    - 提高用户的体验

    前端权限控制的思路:(不限制某一技术,是个解决方案)
    1.菜单的控制(后台管理系统中侧边栏的展示)
    在登陆请求中,会得到权限的数据,需要后端来返回数据作为支持,前端根据后端返回的数据展示对应的菜单,点击菜单,查看对应的界面
    2.界面的控制
    如果用户没有登陆,手动在地址栏输入管理界面的地址,需要跳转到登陆界面
    如果用户已经登陆,手动输入会权限内的地址,则需要跳转到404界面
    3.按钮的控制
    在某个菜单的界面中,需要根据权限数据展示可操作的按钮
    4.请求与响应的控制
    如果用户通过非常规的操作,如通过浏览器的调试工具将禁用的按钮变为可用,发送请求,也应该被拦截,尽管后端会返回错误的状态码,目的是减轻服务器的请求次数

    Vue权限控制的实现:

    1.菜单的控制
    前提:登陆成功后拿到的对应的数据

    {
        "data":{
            "email": "123999@qq.com",
            "id": 500,
            "mobile": "13999999999",
            "rid": 0,
            "token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjUwMCwicmlkIjowLCJpYXQiOjE1MTI1NDQyOTksImV4cCI6MTUxMjYzMDY5OX0.eGrsrvwHm-tPsO9r_pxHIQ5i5L1kX9RX444uwnRGaIM",
            "username": "admin"
        },
        "meta":{
            "msg": "登录成功",
            "status": 200
        },
        "right":[
            {
                "authName": "事件管理",
                "children":[
                    {
                      "authName": "事件添加",
                        "id": 111,
                        "path": "eventAdd",
                        "rights":["view","edit","add","delete"]
                    },
                    ],
                "icon": "icon-user",
                "id": 110
            },  
            {
                 "authName": "系统管理",
                "children": [
                    {
                    "authName": "角色管理",
                    "id": 172,
                    "path": "role",
                    "rights":["view","edit","add","delete"]
                    },
                ],
                "icon": "icon-shangpin",
                "id": 170,
            },
        ]
    }
    

    - token用于前端页面的用户状态的保持
    - right数组,是该用户具备的权限数据,一级权限对应一级菜单,二级权限对应二级菜单
    注意:这些数据是在登陆界面获取到,如果想在首页使用,需要用到vuex来做全局的状态管理
    vuex代码:

    import Vue from 'vue'
    import Vuex from 'vuex'
    Vue.use(Vuex)
    //引入并使用vux,抛出vuex new的对象
    export default new Vuex.Store({
      state: {
        rightList: JSON.parse(sessionStorage.getItem('rightList') || '[]'),
        username: sessionStorage.getItem('username')
        //存储的值位于本地存储中,在这里读取出来存储在state中,页面中也可能用到当前用户的信息,需要的话进行存储,这里只用到了用户名
        //此处需要注如果没有对state中的值进行本地的存储会出现一个bug:页面刷新,vuex中的数据初始化,会变为空,只需要将数据存储在本地存储中,使其与vuex中的数据保持同步即可解决
      },
    //state存储值,不建议在这里面进行更改,要更改使用mutations来定义方法进行更改
      mutations: {
        setRightList(state, data) {
          state.rightList = data
          sessionStorage.setItem('rightList', JSON.stringify(data))
        },
        setUsername(state, data) {
          state.username = data
          sessionStorage.setItem('username', data)
        }
      },
      actions: {
      },
      modules: {
      }
    })
    
    

    login代码:

    //登陆成功后的回调中进行返回信息的存储
                  this.$store.commit("setRightList", res.right);
                  this.$store.commit("setUsername", res.data.username);
                  sessionStorage.setItem("token", res.data.token);
    //token就不需要存储在vuex中,只需要存储在本地即可,在页面需要退出登陆时清空本地存储的值,进行路由的跳转并刷新页面即可将本地存储与vuex中存储的值清空
    

    index代码:

    import { mapState } from "vuex";
    //引入mapState函数并对vuex中的数据做一个映射
    created() {
        this.menulist = this.rightList;
        this.msg=this.username
        //映射出来的值直接赋值使用即可
      },
       computed: {
        ...mapState(['rightList', 'username']),
      },
    //退出登陆清空vuex与本地存储的数据,在退出登陆的方法中写入一下即可:
    logout() {
          sessionStorage.clear();
          setTimeout(() => {
            this.$router.push("/login");
            this.$message.success("退出登陆成功");
          }, 1000);
        //设置延迟执行函数为了用户体验
        },
    

    2.界面的控制

    • 未登录直接访问
      如何判断用户是否登陆?(token)
      前面已经进行token的存储
      什么时机进行判断?(路由导航守卫)
      router.js代码:
    router.beforeEach((to, from, next) => {
     if (to.path === '/login'||to.path==='/register') {
     //如果是跳转到登陆或者注册是不用进行判断
       next()
     } else {
       const token = sessionStorage.getItem('token')
       if(!token) {
       //跳转除登陆注册组件时进行token的判断,如果不存在跳转登陆页面进行登陆
         next('/login')
       } else {
         next()
       }
     }
    })
    
    • 用户已经登陆但是在地址栏输入不具备权限的页面仍然可以访问!
      解决:
      (1).使用路由导航守卫
      固然是可以的,可以在每次地址栏变化时从vuex中取出right进行判断用户将要访问的界面这个用户是否有权限进行访问。
      如果用户不具备权限的路由是否应该是不存在的??
      (2).动态路由的使用
      router.js代码:
    import Users from '@/components/user/Users.vue'
    import Roles from '@/components/role/Roles.vue'
    import GoodsCate from '@/components/goods/GoodsCate.vue'
    import GoodsList from '@/components/goods/GoodsList.vue'
    import store from '@/store'
    //引入组件
    const userRule = { path: '/users', component: Users }
    const roleRule = { path: '/roles', component: Roles }
    const goodsRule = { path: '/goods', component: GoodsList }
    const categoryRule = { path: '/categories', component: GoodsCate }
    //声明变量与vuex中的二级权限的path进行映射关系
    const ruleMapping = {
      'users': userRule,
      'roles': roleRule,
      'goods': goodsRule,
      'categories': categoryRule
    }
    
    export function initDynamicRoutes() {
    //根据二级权限对路由规则的动态添加
      console.log(router)  //这个是路由下的所有路由规则,打印出来更清晰的使用里面的方法
      const currentRoutes = router.options.routes
      const rightList = store.state.rightList
      rightList.forEach(item => {
        item.children.forEach(item => {
          //对二级权限的路由遍历和动态添加
          const itemRule = ruleMapping[item.path]
          itemRule.meta = item.rights
          //对路由新建规则并赋值,返回数据的按钮权限
          currentRoutes[2].children.push(itemRule)
        })
      })
      router.addRoutes(currentRoutes)
    }
    

    注意BUG:此处写完路由文件后,页面刷新为空
    原因:页面刷新,路由重新加载,路由规则变成空,动态路由不存在了
    解决:登陆后添加动态路由,可以放在根组件App.vue中
    App.vue代码:

    import { initDynamicRoutes } from '@/router.js'
     created() {
        initDynamicRoutes()
      }
    //在组件创建时执行这个方法即可解决
    

    login.vue代码:

    import { initDynamicRoutes } from '@/router.js'
    //登陆成功后调用下这个方法即可
    initDynamicRoutes()
    

    3.按钮的控制
    原理:根据返回的数据存储在子路由的权限(增删改查)
    实现: 使用自定义指令来实现
    在src目录下的utils新建permission文件,并且在main.js中调用
    permission.js代码:

    import Vue from 'vue'
    import router from '@/router.js'
    Vue.directive('permission', {
    //注册自定义指令'v-permission'
      inserted: function (el, binding) {
      //当指令插入元素调用时,可以传递两个值:el:指令所在的元素;binding:一个对象,包含当前元素的propety属性
        console.log(el)
        console.log(binding)
        const action = binding.value.action
         //此按钮指令中的值
        const currentRight = router.currentRoute.meta
        //此变量为路由动态添加后的权限的值
        console.log(currentRight)
        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.parentNode.removeChild(el)   //删除
            }
          }
        }
      }
    })
    

    页面中使用:

    <el-button v-permission={action:'add',effect:'disabled'}>删除</el-button>
    //注:如果存在effect:'disabled表示为禁用状态,否则为当前按钮为删除状态,不显示
    

    4.请求响应的控制

    • 请求的控制
      (1)除了登陆注册外的请求都要携带token,用于数据库鉴别身份
      实现:设置请求头
      (2)如果发出了非权限内的请求,应该在前端进行阻断
      原理:根据请求方式的映射关系进行判断
      请求方式:
      查看 get请求
      增加 post请求
      修改 put请求
      删除 delete请求
      http.js代码:
    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') {
        req.headers.Authorization = sessionStorage.getItem('token')
        // 当前模块中具备的权限
        const method = req.method
        // 根据请求, 得到是哪种操作
        const action = actionMapping[method]
        // 判断action是否存在当前路由的权限中
        const rights = router.currentRoute.meta
        if (rights && rights.indexOf(action) == -1) {
          // 没有权限
          alert('没有权限')
          return Promise.reject(new Error('没有权限'))
        }
      }
      return req
    })
    
    • 响应的控制
      如果得到服务器的返回状态码为401,代表token超时或被篡改,此时应跳转到登陆页面
      http.js代码:
    axios.interceptors.response.use(function (res) {
      if (res.data.meta.status === 401) {
        router.push('/login')
        sessionStorage.clear()
        window.location.reload()
      }
      return res
    })
    

    相关文章

      网友评论

          本文标题:Vue后台管理系统权限控制与管理

          本文链接:https://www.haomeiwen.com/subject/wutayktx.html