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中,判断是否登录
在这里插入图片描述
问题: 这样用户在登录之后就可以访问其他界面了,但如果用户A登录之后他只能访问a页面,他不能访问b页面,但是这时候他还是可以通过地址栏输入进入到b页面

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

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

router.options.routes
在这里插入图片描述

登录成功之后动态添加路由,注意这个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属性包含了二级路由
在这里插入图片描述
[{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页面
在这里插入图片描述
问题: 如果我们重新刷新的话动态路由就会消失,动态路由是在登录成功之后才会调用的,刷新的时候并没有调用,所以动态路由没有添加上

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

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

这块使用的就是asiox的请求拦截器设置
在这里插入图片描述
如果发出了非权限内的请求, 应该直接在前端范围内阻止, 虽然这个请求发到服务器也会被拒绝

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

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

Logo

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

更多推荐