vue后台管理系统权限处理

Posted on 2020-03-24 21:07  张雪冬前端学习园地  阅读(1514)  评论(1编辑  收藏  举报

vue后台管理系统权限

 

 

 

1.权限问题用户和管理员进入管理系统看到的模块是不一样的,管理员看的的要比用户看到的多。需要用到动态加载路由,router.addRouters()来动态的挂载路由

// 1.先登录将获取到的用户的token存储起来

// store/index.js

// 封装的api接口方法
import { getLogin, getUserInfo } from '../api/index'


state: {
    roles: [],
    token: window.localStorage.getItem('token') || ''
},


mutations: {

    // 将获取到的token存储到本地
    SET_TOKEN (state, token) {
      state.token = token
      window.localStorage.setItem('token', state.token)
    }
},


actions: {

   userLogin ({ commit }, userInfo) {

      // 返回一个异步回调,promise
      return new Promise((resolve, reject) => {

        // 调用封装好的请求数据的方法
        getLogin(userInfo).then(res => {
          const data = res.data
          if (data.code === 200) {
    
            // 调用mutations中的方法,将token存储到本地中
            commit('SET_TOKEN', data.token)
          }
          resolve(res.data)
        }).catch(error => {
          reject(error)
        })
      })
    },

    
    // 根据用户的token获取用户的个人信息,里面包含了权限信息

    getUserInfo ({ state }) {

        // 返回一个异步回调,promise
      return new Promise((resolve, reject) => {

        // 调用接口方法获取数据
        getUserInfo(state).then(res => {
    
            // 将获取到的信息放到数组中存储
          state.roles.push(res.data)
          resolve(res.data)
        }).catch(error => {
          reject(error)
        })
      })
    }
}


// 在login/index.vue中使用,点击按钮触发
userLogin () {

      this.$store.dispatch('userLogin', this.userInfo).then(res => {
        // 登陆成功跳转主页
        this.$router.push('/home')
      }).catch(error => {
        console.log(error)
      })
}


// vuex的计算属性

getters: {
    // 将用户数据放到计算属性中,一旦数据发生变化,可以重新计算
    roles (state) {
      return state.roles
    },
    token (state) {
      return state.token
    }
},



// 权限模块的处理



// router/index.js

// 路由中的配置

// 静态路由,没有权限的所有用户都可以看到

// 引入登陆页面
import Login from '../views/Login'

export const staticRoutes = [
  {
    path: '/login',
    name: 'login',
    component: Login
  },
  {
    path: '/home',
    name: 'home',
    component: () => import('../views/Home')
  }
]


// 异步(动态)挂载的路由,根据权限展示
export const asyncRouteMap = [
  {
    path: '/details',
    name: 'details',
    component: () => import('../views/Details'),
    meta: {
      role: ['admin', 'super_editor'] // 页面需要的权限
    },
    children: [
      {
        path: 'index',
        name: 'index',
        component: () => import('../views/Details/Child'),
        meta: {
          role: ['admin', 'super_editor'] // 页面需要的权限
        },
        children: [
          {
            path: '/next',
            name: 'next',
            meta: {
              role: ['admin', 'super_editor'] // 页面需要的权限
            }
          }
        ]
      }
    ]
  },
  {
    path: '/error',
    component: () => import('../views/404'),
    name: 404
  },
  { path: '*', redirect: '/error', hidden: true }
]

// 因为可以动态的挂载路由,但是不能动态删除路由。所以才考略到,
// 在需要动态清空动态挂载路由的话,直接将一个新的路由对象赋值给旧的路由对象,这样就可以达到动态清除的工作

const createRouter = () => new VueRouter({
  scrollBehavior: () => ({ y: 0 }),
  routes: staticRoutes
})


const router = createRouter()

// 调用该方法动态清除动态挂载路由
export function resetRouter () {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router



// store/permission.js

// 引入权限路由,和公共路由
import { staticRoutes, asyncRouteMap } from '../router/index' 

// 用来筛选后端返回来的权限数据,和权限路由中的meta里面的数据匹配,匹配成功返回true,失败为false

function hasPerMission (roles, route) {
  if (route && route.meta.role) {
    return roles.some(role => route.meta.role.indexOf(role) >= 0)
  } else {
    return true
  }
}


const permission = {
  state: {
    routers: staticRoutes,
    addRouters: []
  },
  mutations: {

    // 将匹配成功的权限路由拼接到公共路由中
    SET_ROUTERS (state, routers) {
      state.addRouters = routers
      state.routers = staticRoutes.concat(routers)
    }
  },
  actions: {

    // 对后台返回来的权限和动态路由权限匹配
    GenerateRoutes ({ commit }, data) {

        // 返回一个异步回调promise
      return new Promise((resolve, reject) => {

        // 遍历权限路由数组
        const accessedRoutes = asyncRouteMap.filter(v => {

            // 判断如果后台返回的权限中包含admin就是管理员,可以进入权限路由页面
          if (data.indexOf('admin') >= 0) return true

           // 之后就是调用hasPerMission函数对象权限动态路由和后台返回的用户权限进行严格匹配
          if (hasPerMission(data, v)) {
            
            // 判断是否有权限路由是否有子路由,有子路由继续遍历
            if (v.children && v.children.length > 0) {
              v.children = v.children.filter(child => {

                // 对权限子路由和后台返回的用户权限数据,在进行匹配,匹配成功返回
                if (hasPerMission(data, child)) {
                  return child
                }
                
                // 失败返回false
                return false
              })

                // 并且要把权限的父路由返回来,不光要把权限子路由返回,无论权限子路有还是没有,都应该把权限父路由返回来
              return v
            } else {
    
                // 权限父路由匹配成功返回
              return v
            }
          }
    
           // 如果每一个判断都没有进,说明该用户没有任何权限,返回false
          return false
        })
        commit('SET_ROUTERS', accessedRoutes)
        resolve()
      })
    }
  },
  getters: {

    // 只要权限路由数组发生变化就重新计算
    addRouters (state) {
      return state.addRouters
    }
  }
}
export default permission


// 在store/index.js

// 引入另一个模块使用
import permission from './permission'

modules: {

    // 我们还需要用到另一个模块配合完成
    permission
}




// 之后创建一个js文件单独放到全局路由导航,之后在main.js中引入执行

// gloab/index.js

// 先把路由和vuex引进来使用
import router from '../router'
import store from '../store'

const whiteList = ['/login'] // 不重定向白名单

router.beforeEach((to, from, next) => {
  if (store.getters.token) {
    // 判断如果是去登陆页面的话,返回主页,不让他返回登录页
    if (to.path === '/login') {
      next({ path: '/home' })
    } else {
      // 否则判断一下用户的个人信息是否已经拉取完毕
      if (store.getters.roles.length === 0) {
        // 拉取用户个人信息
        store.dispatch('getUserInfo').then(res => {
          // 拿到用户后台返回的权限数据
          const roles = res.role
          // 调用 permission.js方法中的GenerateRoutes方法,将后台返回的用户的权限数据,传递回去进行筛选处理
          store.dispatch('GenerateRoutes', roles).then(() => { // 生成可访问的路由表
            // 将筛选的权限路由数组动态挂载
            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes添加完成
          })
        }).catch(error => {
          console.log(error)
          // 验证失败重新登陆
          next({ path: '/login' })
        })
      } else {
        next() // 当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的页面会自动进入404页面
      }
    }
  } else {
    // 如果已经去了登陆页面了,就不需要再next到登陆页面了,这就是重定向白名单
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next('/login') // 否则全部重定向到登录页
    }
  }
})