vue+elementui搭建後臺管理界面(6登陸和菜單權限控制)

不一樣的權限對應不一樣的路由(菜單),同時側邊欄也根據權限異步生成,實現登陸和鑑權思路以下:前端

  • 登陸:點擊登陸,服務器驗證經過後返回一個 token ,而後存到 cookie,再根據 token 拉取用戶權限
  • 鑑權:經過 token 獲取對應的roles, 計算有權限的路由,使用 router.addRoutes 動態加載路由

數據和操做經過 vuex 進行控制vue

1 登陸

登陸按鈕 click 事件觸發登陸動做:vue-router

/** ...省略的代碼 */
this.$store.dispatch('LoginByUsername', {
    'username': username, 'password': password
})
.then(() => {
    this.logining = false
    this.$notify.success({
    message: '歡迎登陸',
    duration: 3 * 1000,
    })
    // 重定向到首頁
    this.$router.push({ path: this.redirect || '/' })
})
.catch(err => {
    this.logining = false
    this.$alert(err, {
        type: 'warning',
        confirmButtonText: 'ok'
    })
})
/** ...省略的代碼 */

action:vuex

// 登入
LoginByUsername({commit }, userInfo){
    const username = userInfo.username.trim()
    return new Promise((resolve, reject) => {
        loginByUsernameApi(username, userInfo.password)
        .then(response=> {
            const data = response.data
            setToken(data.token) // 儲存token
            commit('SET_TOKEN', data.token)
            commit('SET_ACCOUNT', username)
            resolve()
        })
        .catch(err => {
            reject(err)
        })
    })
}
/** ...省略的代碼 */

登陸成功,服務端返回一個token,而後儲存到本地 cookie。後端

2 獲取用戶權限

對每一個路由,在全局鉤子 router.beforeEach 中攔截,判斷是否已獲取token,以後再獲取用戶的基本信息服務器

/** ...省略的代碼 */
if(store.getters.token) {
    // 判斷當前用戶是否已拉取完user_info信息
    if(store.getters.roles.length === 0){
        // 拉取用戶信息
        store.dispatch('GetUserInfo').then(resp => {
            const roles = resp.data.roles
            next()
            /** ...省略的代碼 */
            })
        })
    }
}
/** ...省略的代碼 */

action:cookie

// 獲取用戶信息, 名稱、頭像、權限
GetUserInfo({commit, state}) {
    return new Promise((resolve, reject) => {
        getLoginUserInfoApi(state.token)
        .then(response => {
            if(!response.data){
                reject('error')
            }
            const data = response.data
            const roles = data.data
            if(roles && roles.length > 0){
                commit('SET_ROLES', roles)
            }else {
                reject()
            }

            if(data.name){
                commit('SET_NAME', data.name)
            }

            if(data.avatar){
                commit('SET_AVATAR', data.avatar)
            }

            response.data.roles = roles
            resolve(response)
        })
        .catch(err => {
            reject(err)
        })
    })
},

3 菜單權限

前端保存一份路由表,記錄每個路由和須要的權限。
再根據用戶信息裏的 roles 計算對應的權限,而後生成有權限的菜單,再掛載路由。
但這只是頁面控制,後端也要相應的作權限驗證。異步

  • 建立vue實例時使用vue-router掛載登陸和一些公用頁面,如首頁、圖表等
  • 用戶登陸後,將獲取的roles和路由表的權限比較,生成用戶可訪問的路由表
  • 調用router.addRoutes添加可訪問的路由
  • 使用vuex管理路由表,生成側邊欄菜單

首先是 router.js 路由表async

import Vue from 'vue'
import Router from 'vue-router'
import Container from '@/containers/Container'
import Login from '@/views/login'
import Page404 from '@/views/404'
import Dashboard from '@/views/dashboard'

/** router modules */
import systemRouter from './modules/system'

Vue.use(Router)

export const constantRouterMap = [
  {
    path: '/login',
    hidden: true,
    component: Login
  },
  {
    path: '/404',
    hidden: true,
    component: Page404
  },
  {
    path: '/',
    redirect: '/dashboard',
    component: Container,
    name: '首頁',
    hidden: false,
    meta: { title: '首頁', icon: '', noCache: true },
    children: [
      {
        path: 'dashboard',
        name: 'Dashboard',
        component: Dashboard,
        meta: { title: '首頁', icon: 'fa fa-dashboard fa-lg', noCache: true }
      },
      {
        path: 'table',
        name: '表格綜合實例',
        component: Form,
        meta: { title: '表格綜合實例', icon: '', noCache: true }
      },
      // { path: '*', redirect: '/404', hidden: true }
    ]
  },
]

export default new Router({
  mode: 'hash',
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRouterMap
})

export const asyncRouterMap = [
  /** 其餘的異步路由表 */
  systemRouter,
  { path: '*', redirect: '/404', hidden: true }
]

同級目錄下的 ./modules/system.js 路由表this

import Container from '@/containers/Container'
/**
 * 系統管理相關路由
 */
const systemRouter = {
  path: '/system',
  component: Container,
  redirect: '/system/permit/account',
  name: '系統管理',
  meta: {
    title: '系統管理',
    roles: ['/system']
  },
  children: [
    {
      path: 'permit',
      name: '權限管理',
      hidden: false, 
      redirect: '/system/permit/account',
      component: () => import('@/views/system/permit'),
      meta: { 
        title: '權限管理', 
        icon: 'fa fa-cog fa-lg',
        roles: ['/system/permit']  
      },
      children: [
        { path: 'account', name: '用戶', 
          component: () => import('@/views/system/permit/account'), 
          meta: { title: '用戶', icon: 'form', roles: ['/system/permit/account'] } 
        },
        { path: 'accountgroup', name: '用戶組',  
          component: () => import('@/views/system/permit/accountgroup'), 
          meta: { title: '用戶組', icon: 'form', roles: ['/system/permit/accountgroup'] } 
        },
        { path: 'role', name: '角色', 
          component: () => import('@/views/system/permit/role'),
           meta: { title: '角色', icon: 'form', roles: ['/system/permit/role'] } 
        },
        { path: 'authorize', name: '受權', 
          component: () => import('@/views/system/permit/authorize'),
           meta: { title: '受權', icon: 'form', roles: ['/system/permit/authorize'] } 
        },
      ]
    },
        
  ],
}

export default systemRouter

roles: ['/system/permit/account'] 表示該頁面須要的權限是 '/system/permit/account' 後端返回的 roles 裏有這個記錄則能訪問對應的頁面
而 '/system/permit/account' 是 '/system/permit' 的子路由,因此要訪問 '/system/permit/account',後端返回:

roles: ['/system', '/system/permit', '/system/permit/account']

注意: 404頁面要最後加載,若是放在 constantRouterMap 中,全部後面的頁面都會被攔截到404

相關文章
相關標籤/搜索