路由及权限

导引

对于cms、hrm、OA等系统开发,通常会有不同权限访问页面限制的问题,不同的身份的人,进入到系统之后,可以看到不同的菜单,进入不同的路由页面。

思路

用户登陆成功,后端接口会返回角色( 普通管理员,超级管理员) ,不同的角色可以访问不同的页面。

思路:
(1)对所有的路由页面分成两类:

  • 公共的,不需要权限即可访问
  • 动态的,只针对不同的权限显示。
    • 提前把所有页面所有可访问条件全部设置。

(2) 当登陆成功之后,获取当前用户的角色,去路由配置中,动态分析,创建当前用户可以访问的路由匹配,保存vuex中,生成菜单。

router配置

在这里插入图片描述

src/index.js 路由中配置动态路由

import Vue from 'vue'
import VueRouter from 'vue-router'
import Index from '../views/Index.vue'

Vue.use(VueRouter)

// 公共页面 - 不需要登陆就可以访问的页面
export const publicRoutes = [
  {
    path: '/',
    name: 'index',
    component: Index,
    // title 用来生成菜单
    meta: { title: '主页' }
  },
  {
    path: '/login', // (ip)
    name: 'Login', // 域名
    meta: { title: '登录' },
    component: () => import('../views/Login.vue')
  },
  {
    path: '*',
    name: 'page404',
    component: () => import('../views/404.vue')
  }
]

// 动态页面
// ptgly: 普通管理员
// cjgly: 超级管理员
export const asyncRoutes = [
  {
    path: '/admin',
    name: 'admin',
    component: () => import('../views/Admin'),
    // roles: 角色
    // 只能普通管理员才能访问
    meta: { title: '管理员', roles: ['ptgly'] }
  },
  {
    path: '/superadmin',
    name: 'superadmin',
    component: () => import('../views/SuperAdmin'),
    // 只能超级管理员才能访问
    meta: { title: '超级管理员', roles: ['cjgly'] }
  },
  {
    path: '/adminindex',
    name: 'adminindex',
    component: () => import('../views/AdminIndex'),
    // 超级管理员, 普通管理员都能访问
    meta: { title: '管理员页面1', roles: ['cjgly', 'ptgly'] }
  }
]

// 初始的路由配置只提供 公共页面 的配置
const router = new VueRouter({
  routes: publicRoutes
})

export default router

通过meta:来额外补充信息

src\router\permission 封装当前角色可以访问路由的方法

src\router\permission.js

// 导入 路由配置
import { asyncRoutes, publicRoutes } from './index'

/**
 * 根据角色不同,获取对应能够访问到的路由页面配置
 * @param {*} role 角色 cjgly
 */
export const buildRoute = function (role) {
  const routes = []
  // 在需要权限才能访问的路由asyncRoutes中,找出当前角色能够访问的
  // 路由 遍历当前角色可以访问的路由
  asyncRoutes.forEach(route => {
    if (route.meta.roles && route.meta.roles.includes(role)) {
      routes.push(route)
    }
  })

  return {
    asyncRoutes: routes, // 动态分析出来的权限页面
    allRoutes: [...publicRoutes, ...routes]
    // 当前用户可以访问的所有的页面 公共页面 + 动态分析出来的权限页面
    // 保存到vuex中,后来用来动态生成菜单
  }
}

登陆页:动态添加路由配置

import { buildRoute } from '../router/permission'
async login () {
      let roleInfo = {}
      // roleInfo = await ajax({
      //   methods: 'get',
      //   // url: '/app/v1_0/channels'
      //   url: 'api/v1_0/user'
      // })
      // console.log(roleInfo)

      // 模拟请求后端接口
      if (this.name === 'admin') {
        roleInfo = { name: 'admin', role: 'cjgly' }
      } else if (this.name === 'fan') {
        roleInfo = { name: 'fan', role: 'ptgly' }
      } else {
        alert('用户名错误')
        return
      }

      // 保存用户信息到vuex
      this.$store.commit('setUserInfo', roleInfo)

      // 根据角色去获取当前用户能够访问的路由配置
      const { asyncRoutes, allRoutes } = buildRoute(roleInfo.role)

      // 保存当前用户所有可以访问的路由到vuex中
      this.$store.commit('setRoutes', allRoutes)

      // 动态添加路由配置
      this.$router.addRoutes(asyncRoutes)

      // 进行页面的跳转
      this.$router.push(this.$route.query.backto || '/adminindex')
    }

vuex

保存用户信息

  • 姓名

  • 角色

  • 当前所拥有的路由

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    userInfo: { name: undefined, role: undefined },
    routes: []
  },
  mutations: {
    // 设置用户信息
    setUserInfo (state, userInfo) {
      const { name, role } = userInfo
      state.userInfo.name = name
      state.userInfo.role = role
    },
    // 设置路由信息
    setRoutes (state, routes) {
      state.routes = routes
    }
  },
  getters: {
    gIsLogin (state) {
      // 根据当前登陆信息中的用户名来判断是否登陆
      return !!state.userInfo.name
    },
    routes (state) {
      // 对当前所有能访问的页面进行过滤
      return state.routes.filter(route => route.name !== 'page404' && route.name !== 'Login' && route.meta && route.meta.title).map(route => ({
        title: route.meta.title,
        path: route.path
      }))
    }
  }
})

全局路由守卫

src\permission.js

import router, { publicRoutes } from './router'
// 导入vuex
import store from './store'

// 白名单: 不需要登陆就可以访问的页面
const whiteList = publicRoutes.map(route => route.path)

// 全局路由守卫
router.beforeEach((to, from, next) => {
  // 是否有角色
  const currentRole = store.state.userInfo.role
  if (currentRole) {
    next()
  } else {
    // 是否在白名单
    if (whiteList.includes(to.path)) {
      next()
    } else {
      next('/login?backto=' + to.fullPath)
    }
  }
})

生成菜单APP.vue

<div id="nav">
      <router-link
        v-for="item in $store.getters.routes"
        :key="item.path" :to="item.path">{{item.title}}
      </router-link>
      <!-- <router-link to="/about">About</router-link> -->
      <button v-if="$store.getters.gIsLogin" @click="hLogout">退出</button>
    </div>

同一页面,不同身份看到的按钮不一样

在这里插入图片描述
思路:

  1. 在vuex中取出角色,根据角色不同的,来通过v-show,v-if来控制显示。

    <div v-if="$store.state.userInfo.role==='cjgly'"> 只有超级管理员可见 </div>
    
  2. 自定义指令

指令

作用:根据角色对元素进行约束:如果角色不对,就不显示出来。

directives

定义

src\directive\permission.js

// 以vue插件的格式来封装一个自定义指令
// 它的作用是:
//    根据当前用户的角色(vuex中取)与用户传入参数比较,决定是否要显示
//    当前的元素
import store from '../store/index'

export default {
  // 在Vue.use(对象),它会自动去调用对象的install方法,并传入Vue构造器
  install: function (Vue) {
    Vue.directive('permission', {
      // https://cn.vuejs.org/v2/guide/custom-directive.html#%E9%92%A9%E5%AD%90%E5%87%BD%E6%95%B0
      inserted: function (el, binding) {
        console.log(el, binding)
        // <button v-permission="['cjgly']">按钮</button>
        // binding.value 就是['cjgly']
        const routes = binding.value
        if (routes && Array.isArray(routes) && routes.length) {
          const role = store.state.userInfo.role
          if (role && routes.includes(role)) {
            // 说明ok
          } else {
            // 如果角色不在允许范围,则移除dom
            el.parentNode.removeChild(el)
          }
        }
      }
    })
  }
}

引入

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './permission.js'

// 以插件的格式使用自定义指令
import directive from './directive/permission'
Vue.use(directive)

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

使用

在任意组件:

<button v-permission="['cjgly', 'ptgly']">普通管理员和超级管理员都可以看到的按钮</button>
<button v-permission="['cjgly']">超级管理员才能看到的按钮</button>
  • 10
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 umi 中实现路由权限可以通过以下几个步骤: 1. 在路由配置文件中定义路由时,可以添加一个 `authority` 属性来标识该路由需要的权限。比如: ``` routes: [ { path: '/', component: '@/pages/index', authority: ['admin', 'user'] }, ... ] ``` 2. 在应用程序中,可以通过一些方式获取当前用户的权限列表。比如从后端接口获取、从浏览器缓存中获取等等。 3. 在应用程序中,可以编写一个 `Authorized` 组件来控制路由是否可以渲染。该组件可以接收一个权限列表作为参数,然后根据当前用户的权限列表和路由配置中的权限要求,来判断当前路由是否可以渲染。比如: ``` import React from 'react'; import { Redirect, Route } from 'umi'; const Authorized = ({ children, authority }) => { // 获取当前用户的权限列表 const currentUserAuthority = ['admin', 'user']; // 判断当前路由是否可以渲染 if (authority.some(item => currentUserAuthority.includes(item))) { return children; } else { return <Redirect to="/403" />; } }; export default Authorized; ``` 4. 在路由配置文件中使用 `Authorized` 组件来包装需要进行权限控制的路由即可。比如: ``` routes: [ { path: '/', component: '@/layouts/index', routes: [ { path: '/', component: '@/pages/index', authority: ['admin', 'user'], wrapper: Authorized }, ... ] }, ... ] ``` 这样,只有当当前用户的权限列表中包含该路由需要的权限时,该路由才会被渲染出来。否则,用户将被重定向到 403 页面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值