vue中路由全局前置守卫/权限设置

281 阅读3分钟

大多数会在全局前置守卫router.beforeEach()里,做如下操作:

一. 先判断有没有token,有token,证明是登陆状态;

  1. 在第一步里接着判断想去哪个路由组件?有以下两种情况
  • (1)去的是登录页面,直接调用next({path:'/'})重定向为首页;

  • (2)取得不是登录页,先判断有没有用户名,该用户名是在进入首页之前dispatch获取的,存到了store里,是否有用户名也是分为两种情况,如下:

    • a:有用户名,可以直接调用next(),去他想去的路由组件;
    • b:如果没有,先异步store.dispatch(这里的action和进入首页的action是同一个),请求成功之后,去用户刚刚想去的页面;请求失败的话异步store.dispatch('user/resetToken'),声明错误,调用 next(/login?redirect=${to.path}),说明这时候token已经失效,在该action里清除token,并且重新设置token

二.没有token做如下操作:

 /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }

router.beforeEach()整体代码如下:

import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'

NProgress.configure({ showSpinner: false }) // NProgress Configuration

const whiteList = ['/login'] // no redirect whitelist

router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        try {
          // get user info
          await store.dispatch('user/getInfo')
          
          next({
            ...to,
            replace:true
          })
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  // finish progress bar
  NProgress.done()
})

router.beforeEach()中相关的dispatch

const actions = {
   //获取登录的用户信息
    getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
       
        const { data } = response
        console.log(data,'111')
        if (!data) {
          return reject('Verification failed, please Login again.')
        }
        commit('SET_USERINFO',data);
  },
  //重新设置token1
    resetToken({ commit }) {
    return new Promise(resolve => {
      removeToken() // must remove  token  first
      commit('RESET_STATE')
      resolve()
    })
  }
}

//重新设置token2
const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  }

以下是router.beforeEach的全局前置守卫和一些计算异步路由---即权限路由-->根据服务器返回的信息设置用户权限

import { login, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { resetRouter,anyRoutes,asyncRoutes ,constantRoutes} from '@/router'
import router from "@/router"
const getDefaultState = () => {
  return {
    token: getToken(),
    name: '',
    avatar: '',//存储头像

    // 服务器返回的菜单信息【根据不同用户、角色但会的标记信息,数组里卖能的元素是字符串】
    routes:[],//菜单
    roles:[],//角色
    buttons:[],//按钮

    // 对比之后--项目中已有的异步路由,与服务器返回的标记信息进行对比,得到最重要展示的而路由
    resultAsyncRoutes:[],
    resultAllRoutes:[]//最终的要展示的路由
  }
}

const state = getDefaultState()

const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  // 存储用户信息--name,头像、
  SET_USERINFO(state,userInfo){
   // 存储服务器请求回来的用户信息--用户名
   state.name=userInfo.name;
   // 存储服务器请求回来的用户信息--头像
   state.avatar=userInfo.avatar;
   // 存储服务器请求回来的用户信息--菜单权限标记
   state.buttons=userInfo.buttons;
    // 存储服务器请求回来的用户信息--角色权限标记
   state.roles=userInfo.roles;
    // 存储服务器请求回来的用户信息--用户权限标记
    state.routes=userInfo.routes
 },
//  最终计算出的异步路由
SET_RESULTASYNCROUTES(state,asyncRoutes){
  // 当前只是保存用户的异步路由,每个用户还要有常量路由和任意路由
   state.resultAsyncRoutes=asyncRoutes;

   state.resultAllRoutes=constantRoutes.concat(state.resultAsyncRoutes,anyRoutes);
   console.log(state.resultAllRoutes,'aaa')
  //  给路由添加动态路由
   router.addRoutes(state.resultAllRoutes)
}
}

// 计算有哪些异步路由的函数
 function computedAsyncRoutes(asyncRoutes,routes){
  //过滤当前用户【超级管理员|普通员工】需要展示的异步路由
  return asyncRoutes.filter(item=>{
    //判断routes种是否有item对象--item就是routes里的异步路由路由,在router的里
    if(routes.indexOf(item.name)!==-1){
      // 每个而路由可能有二、三四五六级路由,所以利用递归在进行遍历
      if(item.children && item.children.length){
        item.children=computedAsyncRoutes(item.children,routes)
      }  
      return true;//这里返回的是符合条件的item对象-->异步路由
    }
  })
}
const actions = {
  // 在这里处理登录业务
  async login({ commit }, userInfo) {
    // 解构出携带过来的参数
    const { username, password } = userInfo
    const result = await login({ username: username.trim(), password: password })
    console.log(result)
    if (result.code === 20000) {
      const { data } = result
      commit('SET_TOKEN', data.token)
      setToken(data.token)
      return 'ok'
    } else {
      return Promise.reject(new Error('faile'))
    }
  },

  // get user info
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
       
        const { data } = response
        console.log(data,'111')
        if (!data) {
          return reject('Verification failed, please Login again.')
        }
        commit('SET_USERINFO',data);

        // 计算异步路由
        //computedAsyncRoutes()方法是过滤哪些要显示的异步路由--即权限路由
        commit('SET_RESULTASYNCROUTES',computedAsyncRoutes(asyncRoutes,data.routes))
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // user logout
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout(state.token).then(() => {
        removeToken() // must remove  token  first
        resetRouter()
        commit('RESET_STATE')
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // remove token
  resetToken({ commit }) {
    return new Promise(resolve => {
      removeToken() // must remove  token  first
      commit('RESET_STATE')
      resolve()
    })
  }
}

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