权限管理(Vue)

VUE权限管理

思路:在login.vue中登录成功时,后端会返回token和该用户对应的权限,前端根据权限数据, 展示对应的菜单。点击菜单, 才能查看相关的界面。
但是在login.vue获得的权限数据要在home.vue中使用,所以要把请求来的权限数据保存到vuex中
login方法和权限方法

export const login = data => {
  return request({
    url: '/login',
    method: 'POST',
    data
  })
}
// 获取用户权限
export const getRoles = data => {
  return request({
    url: '/roles',
    method: 'POST',
    data
  })
}

login方法调用

 login(this.form).then(res => {
        // console.log(res, 'login=>res')
        // 将用户身份存入vuex 普通用户身份: student 管理员用户身份: admin
        this.$store.commit('setRole', res.data.role)
        this.$store.commit('setUsername', res.data.username)
        this.$store.commit('setPhoto', res.data.photo)
        sessionStorage.setItem('token', res.data.token)

        getRoles(res.data.role).then(ret => {
          // console.log(ret.data, 'getRoles=>ret.data')
          // 将对应身份下的路由存储到vuex
          this.$store.commit('setRightList', ret.data)
          this.loading = false
          this.$message.success('登陆成功')

          // 根据用户所具备的权限 动态添加路由规则
          initDynamicRoutes()
          this.$router.push('/')
        })
      })

vuex
注意这里为什么要把数据保存到sessionStorage?
因为这样当在home.vue刷新时,页面的权限数据不会丢失。不然直接保存数据页面刷新重新获取的时候是没有login的登录请求的,所以请求不到数据。

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    role: sessionStorage.getItem('role'),
    rightList: JSON.parse(sessionStorage.getItem('rightList') || '[]'),
    username: sessionStorage.getItem('username'),
    photo: sessionStorage.getItem('photo')
  },
  mutations: {
    setRole (state, data) {
      state.role = data
      sessionStorage.setItem('role', data)
    },
    setRightList (state, data) {
      state.rightList = data
      sessionStorage.setItem('rightList', JSON.stringify(data))
    },
    setUsername (state, data) {
      state.username = data
      sessionStorage.setItem('username', data)
    },
    setPhoto (state, data) {
      state.photo = data
      sessionStorage.setItem('photo', data)
    }
  },
  actions: {},
  getters: {}
})

在home.vue使用权限数据是通过mapState结合computed使用
mapState作用就是把权限数据映射到home.vue中

import { mapState } from 'vuex'
 computed: {
    ...mapState(['username']), // 用户名
    ...mapState(['photo']) // 用户头像
  },

退出登录逻辑
清除sessionStorage和Vuex的数据即可
这里注意,清除vuex的数据是删除完sessionStorage,然后将页面刷新即可
因为vuex的数据是通过sessionStorage取出的

logout () {
      sessionStorage.clear()
      this.$router.push({ name: 'login' })
      // 删除vuex中的数据 让当前页面刷新
      window.location.reload()
    }

界面的控制

登录成功后,将token数据存储在sessionStorage中,判断是否登录
权限管理(Vue)_第1张图片
问题: 这样用户在登录之后就可以访问其他界面了,但如果用户A登录之后他只能访问a页面,他不能访问b页面,但是这时候他还是可以通过地址栏输入进入到b页面

解决: 当然我们也可以设置路由导航守卫,但是如果有多个页面,设置会非常不方便,并且对于用户A来说,它是不用访问b页面的,这时候我们何不对A不显示b页面,这个时候我们就用到了动态路由
2. 动态路由
router.js
根据当前用户所拥有的的权限数据来动态添加所需要的路由
先定义好所有的路由规则
权限管理(Vue)_第2张图片
定义路由规则和字符串的映射关系
ruleMapping的键是后端返回的path,值是路由规则名

const ruleMapping = {
  table: tableRule,
  users: userRule,
  image: imageRule
}

router.options.routes
权限管理(Vue)_第3张图片

登录成功之后动态添加路由,注意这个initDynamicRoutes的方法需要暴露出去在登录页面调用
currentRoutes[1].children就是home页面的子路由

export function initDynamicRoutes () {
  // console.log(router)
  // 根据二级权限 对路由规则进行动态的添加
  const currentRoutes = router.options.routes
  // currentRoutes[2].children.push()
  const rightList = store.state.rightList
  // console.log(rightList)
  rightList.forEach(item => { // 如果是没有子路由的话 就直接添加进去 如果有子路由的话就进入二级权限遍历
    // console.log(item, 'item-1')
    if (item.path) {
      const temp = ruleMapping[item.path]
      // 路由规则中添加元数据meta
      temp.meta = item.rights
      currentRoutes[1].children.push(temp)
    }

    item.children.forEach(item => {
      // item 二级权限
      // console.log(item, 'item-2')
      const temp = ruleMapping[item.path]
      // 路由规则中添加元数据meta
      temp.meta = item.rights
      currentRoutes[1].children.push(temp)
    })
  })
  // console.log(currentRoutes)
  router.addRoutes(currentRoutes)
}

admin用户的rightLIst包含两项,基本页面和用户权限,其children属性包含了二级路由
权限管理(Vue)_第4张图片
[{id: 1, authName: “基本页面”, icon: “el-icon-connection”,…},…]
0: {id: 1, authName: “基本页面”, icon: “el-icon-connection”,…}
authName: “基本页面”
children: [{id: 11, authName: “表格页面”, icon: “el-icon-s-grid”, path: “table”,…},…]
0: {id: 11, authName: “表格页面”, icon: “el-icon-s-grid”, path: “table”,…}
authName: “表格页面”
icon: “el-icon-s-grid”
id: 11
path: “table”
rights: [“view”, “edit”, “add”, “delete”]
1: {id: 12, authName: “素材页面”, icon: “el-icon-s-marketing”, path: “image”,…}
authName: “素材页面”
icon: “el-icon-s-marketing”
id: 12
path: “image”
rights: [“view”, “edit”, “add”, “delete”]
icon: “el-icon-connection”
id: 1
1: {id: 2, authName: “用户权限”, icon: “el-icon-set-up”,…}
authName: “用户权限”
children: [{id: 21, authName: “权限页面”, icon: “el-icon-s-custom”, path: “users”,…}]
0: {id: 21, authName: “权限页面”, icon: “el-icon-s-custom”, path: “users”,…}
authName: “权限页面”
icon: “el-icon-s-custom”
id: 21
path: “users”
rights: [“view”, “edit”, “add”, “delete”]
icon: “el-icon-set-up”
id: 2
这样当用户A在地址栏输入自己不能访问的路由时,则不会跳转到该页面,跳转到404页面
权限管理(Vue)_第5张图片
问题: 如果我们重新刷新的话动态路由就会消失,动态路由是在登录成功之后才会调用的,刷新的时候并没有调用,所以动态路由没有添加上

解决: 可以在app.vue中的created中调用添加动态路由的方法
权限管理(Vue)_第6张图片
按钮的控制
虽然用户可以看到某些界面了, 但是这个界面的一些按钮该用户可能是没有权限的。 因此, 我们需要对组件中的一些按钮进行控制, 用户不具备权限的按钮就隐藏或者禁用, 而在这块的实现中, 可以把该逻辑放到自定义指令中

比如我们可以根据后端返回的数据right来判断用户有什么权限,如下图
权限管理(Vue)_第7张图片
添加自定义指令 控制按钮permission.js放到utils文件夹里面
权限管理(Vue)_第8张图片
权限管理(Vue)_第9张图片
请求和相应的控制
除了登录请求都得要带上token , 这样服务器才可以鉴别你的身份

这块使用的就是asiox的请求拦截器设置
权限管理(Vue)_第10张图片
如果发出了非权限内的请求, 应该直接在前端范围内阻止, 虽然这个请求发到服务器也会被拒绝

非权限内的请求:比如a用户是不能够操作该页面的按钮的,但是他通过f12调试把按钮改为可点击,如果我们不对这个请求进行处理,那么这个请求就会发送出去
权限管理(Vue)_第11张图片
响应控制
到了服务器返回的状态码401, 代表token 超时或者被篡改了,此时应该强制跳转到登录界面
权限管理(Vue)_第12张图片
小结
前端权限的实现之须要后端提供数据支持, 否则无法实现。
返回的权限数据的结构, 前后端需要沟通协商怎样的数据便用起来才最方便

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

你可能感兴趣的:(vue.js,前端,javascript)