vue-router路由拦截+重定向处理权限控制

1.创建路由文件router.js

写入项目的路由配置。

import Vue from 'vue'
import Router from 'vue-router'

const originalPush = Router.prototype.push
Router.prototype.push = function push(location, onResolve, onReject) {
  if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
  return originalPush.call(this, location).catch(err => err)
}

Vue.use(Router)

import Layout from '@/layout'

import adminRouter from './modules/adminRouter'

export const constantRoutes = [
  {
    path: '/redirect',
    component: Layout,
    hidden: true,
    children: [
      {
        path: '/redirect/:path(.*)',
        component: () => import('@/views/redirect/index')
      }
    ]
  },
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },
  {
    path: '/404',
    component: () => import('@/views/error-page/404'),
    hidden: true
  },
  {
    path: '/401',
    component: () => import('@/views/error-page/401'),
    hidden: true
  },
  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
      path: 'dashboard',
      name: '首页',
      component: () => import('@/views/dashboard/index'),
      meta: { title: '首页', icon: 'dashboard', affix: false }
    }]
  },
  adminRouter,
  { path: '*', redirect: '/404', hidden: true }
]

export const asyncRoutes = []

const createRouter = () => new Router({
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
})

const router = createRouter()

export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // 复位路由
}

export default router

2.创建基于vuex的store.js

写入项目的登录,获取用户信息,菜单权限,角色权限等全局方法

import { login, logout, getInfo, queryCurrentAuthority } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import router, { resetRouter, asyncRoutes, constantRoutes } from '@/router'

const state = {
  token: getToken(),
  name: '',
  id: '',
  nickname: '',
  phone: '',
  address: '',
  roles: [],
  routes: [],
  addRoutes: []
}

const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_ID: (state, id) => {
    state.id = id
  },
  SET_NICKNAME: (state, nickname) => {
    state.nickname = nickname
  },
  SET_PHONE: (state, phone) => {
    state.phone = phone
  },
  SET_ADDRESS: (state, address) => {
    state.address = address
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles
  },
  SET_ROUTES: (state, { routes, menus }) => {
    state.addRoutes = routes
    const menusPath = filterAuthority(JSON.parse(menus))
    state.routes = filterConstantRoutes(constantRoutes, menusPath)
  }
}

const actions = {
  // 登录
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        commit('SET_TOKEN', response.data.tokenValue)
        setToken(data.tokenValue)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // 获取用户信息
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        const data = response.data

        if (!data) {
          reject('验证失败,请重新登录。')
        }

        const { roles, name, id, nickname, phone, address } = data

        // 角色必须是非空数组
        if (!roles || roles.length <= 0) {
          reject('角色必须为非null数组!')
        }

        commit('SET_ROLES', roles)
        commit('SET_NAME', name)
        commit('SET_ID', id)
        commit('SET_NICKNAME', nickname)
        commit('SET_PHONE', phone)
        commit('SET_ADDRESS', address)
        commit('SET_PROFILE', profile)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // 获取用户权限
  queryCurrentAuthority({ commit, state, dispatch }) {
    return new Promise((resolve, reject) => {
      queryCurrentAuthority({ username: state.name }).then(response => {
        const data = JSON.stringify(response.menu)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // 登出
  logout({ commit, state, dispatch }) {
    return new Promise((resolve, reject) => {
      logout(state.token).then(() => {
        commit('SET_TOKEN', '')
        commit('SET_ROLES', [])
        removeToken()
        resetRouter()
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // 删除令牌
  resetToken({ commit }) {
    return new Promise(resolve => {
      commit('SET_TOKEN', '')
      commit('SET_ROLES', [])
      removeToken()
      resolve()
    })
  },

  // 动态修改权限
  async changeRoles({ commit, dispatch }, role) {
    const token = role + '-token'

    commit('SET_TOKEN', token)
    setToken(token)

    const { roles } = await dispatch('getInfo')

    resetRouter()

    // 基于角色生成路由
    const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })
    // 动态添加可访问的路由
    router.addRoutes(accessRoutes)
  },

  // 生成路由
  generateRoutes({ commit }, { roles, menus }) {
    return new Promise(resolve => {
      const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
      commit('SET_ROUTES', { accessedRoutes, menus })
      resolve(accessedRoutes)
    })
  }
}

/**
 * 使用meta.role确定当前用户是否具有权限
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    return roles.some(role => route.meta.roles.includes(role))
  } else {
    return true
  }
}

/**
 * 通过递归过滤异步路由
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles) {
  const res = []

  routes.forEach(route => {
    const tmp = { ...route }
    if (hasPermission(roles, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    }
  })

  return res
}

/**
 * 递归菜单权限中路由地址
 * @param {*} menus
 * @returns pathList
 */
export function filterAuthority(menus) {
  const pathList = []

  menus.forEach(route => {
    const tmp = { ...route }
    if (tmp.routes) {
      tmp.routes = filterAuthority(tmp.routes)
      tmp.routes.forEach(path => {
        pathList.push(path)
      })
    }
    pathList.push(tmp.path)
  })

  return pathList
}

/**
 * 根据菜单权限中的路由比较全部路由过滤出可用路由
 * @param {*} routes
 * @param {*} menusPath
 * @returns res
 */
export function filterConstantRoutes(routes, menusPath) {
  const res = []

  routes.forEach(route => {
    const tmp = { ...route }
    if (tmp.children) {
      tmp.children = filterConstantRoutes(tmp.children, menusPath)
    }
    if (menusPath.toString().indexOf(tmp.path) !== -1) {
      res.push(tmp)
    }
  })

  return res
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

根据权限生成路由表 

3.创建路由拦截权限控制permission.js

import router from './router'
import store from './store'
import { getToken } from '@/utils/auth' // 获取令牌
const whiteList = ['/login', '/auth-redirect'] // 重定向白名单

router.beforeEach(async(to, from, next) => {
  // 确定用户是否已登录
  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      // 如果已登录,重定向到主页
      next({ path: '/' })
    } else {
      // 判断是否有角色
      const hasRoles = store.getters.roles && store.getters.roles.length > 0

      if (hasRoles) {
        next()
      } else {
        try {
          // 从用户信息中获取用户对应角色组
          // 角色必须是对象数组!例如: ['ROLE_ADMIN']或['ROLE_DEVELOPER','ROLE_EDITOR']
          const { roles } = await store.dispatch('getInfo')
          // 获取菜单权限中菜单
          const menus = await store.dispatch('queryCurrentAuthority')
          // 基于角色,菜单权限生成可访问的路由
          const accessRoutes = await store.dispatch('generateRoutes', { roles, menus })
          // 动态添加可访问的路由
          router.addRoutes(accessRoutes)

          // 设置replace:true,不会留下历史记录
          next({ ...to, replace: true })
        } catch (error) {
          // 删除令牌并转到登录页面重新登录
          await store.dispatch('resetToken')
          next(`/login?redirect=${to.path}`)
        }
      }
    }
  } else { // 没有令牌

    if (whiteList.indexOf(to.path) !== -1) {
	  // 在登录白名单中,直接进入
      next()
    } else {
	  // 没有访问权限的其他请求将重定向到登录页面。
      next(`/login?redirect=${to.path}`)
    }
  }
})

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值