前後端分離實踐:基於vue實現網站前臺的許可權管理

weixin_34370347發表於2018-01-15

Javascript做為當下的熱門語言,用途很廣泛,從前端到後端處處可見其存在,該技術如今在我們專案內部也大量使用來開發諸如CMS系統以及其他其他一些資料分析系統的前端頁面,為此個人非常感興趣並將其作為帽子卡的擴充套件內容來進行課餘學習。


Javascript框架鱗次櫛比,但基本原理大致相同,因此選用國內人開發的vue.js進行一個初步的嘗試。學習vue.js也一週多的時間了,說起vue的主要用法,無外乎Declarative Rendering、Component System、Client-side Routing、Vue-resource、Axios以及視專案大小而決定是否使用的Vuex,學習vue事小,主要轉變思維,面向前後端分離的元件式web開發才是真正想去實踐的。


正好我的個人網站CodeSheep最近要開發後臺管理,因此正好用vue這一套來實現了一下。說到後臺管理,繞不開的問題就是許可權的管理。既然想實踐前後端分離這種思想,因此後臺管理的所有web前端的東西應該獨立由前端完成,這其中就包括很重要的由前端來根據許可權進行相關東西的控制。我們想要做到的是:不同的許可權對應著不同的路由,同時頁面側邊欄也應該根據不同的許可權,來非同步生成對應的選單,講白了就是後臺管理時不同許可權的使用者其看到的介面選單是不一樣的,因此有了這裡實現登入和許可權驗證的一套流程。

具體實現

1、點選“登入”按鈕觸發登入事件

this.$store.dispatch('LoginByEmail', this.loginForm).then(() => {
  this.$router.push({ path: '/' }); //登入成功之後重定向到首頁
}).catch(err => {
  this.$message.error(err); //登入失敗提示錯誤
});
複製程式碼

其中非同步觸發的actions LoginByEmail的處理內容如下:

LoginByEmail ({ commit }, userInfo) {
      const email = userInfo.email.trim()
      return new Promise((resolve, reject) => {
        loginByEmail(email, userInfo.password).then(response => {
          const data = response.data
          setToken(response.data.token)
          commit('SET_TOKEN', data.token)
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    }
複製程式碼

很容易看出想做的是將從伺服器端拿到的token(唯一標示使用者身份)放到瀏覽器本地Cookie中去

2、全域性鉤子router.beforeEach中攔截路由

這一步是核心,具體處理流程示意如下:

路由攔截處理流程

具體程式碼如下:

router.beforeEach((to, from, next) => {
  if (getToken()) {  // 判斷是否取到token
    if (to.path === '/login') {
      next({ path: '/' })
    } else {
      if (store.getters.roles.length === 0) {  // 判斷當前使用者是否已獲取完user_info資訊
        store.dispatch('GetInfo').then(res => { // 獲取user_info
          const roles = res.data.role
          store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可訪問的路由表
            router.addRoutes(store.getters.addRouters)  // 動態新增可訪問路由表
            next({ ...to }) // 放行路由
          })
        }).catch(() => {
          store.dispatch('FedLogOut').then(() => {
            next({ path: '/login' })
          })
        })
      } else {
        next() // 放行該路由
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) { // 在免登入白名單裡的路徑,繼續讓其訪問
      next()
    } else { // 其他不在白名單裡的路徑全部讓其重定向到登入頁面!
      next('/login')
      alert('not in white list, now go to the login page')
    }
  }
})
複製程式碼

流程圖中幾個重要步驟解釋一下:

  • 判斷前端是否取到了token令牌:getToken()

操作很簡單,主要是從Cookie中獲取,看token是不是已經拿到了:

export function getToken () {
  return Cookies.get(TokenKey)
}
複製程式碼
  • vuex非同步操作store.dispatch('GetInfo'):獲取使用者資訊
    GetInfo ({ commit, state }) {
      return new Promise((resolve, reject) => {
        getInfo(state.token).then(response => {
          const data = response.data
          console.log(data)
          commit('SET_ROLES', data.role)
          commit('SET_NAME', data.name)
          resolve(response)
        }).catch(error => {
          reject(error)
        })
      })
    }
複製程式碼

操作也很簡單,用一個get的restful api從伺服器獲取使用者的角色和名字

  • vuex非同步操作store.dispatch('GenerateRoutes', { roles }):根據不同的roles來生成不同的前臺路由
    GenerateRoutes ({ commit }, data) {
      return new Promise(resolve => {
        const { roles } = data
        let accessedRouters
        if (roles.indexOf('admin') >= 0) {
          accessedRouters = asyncRouter
        } else {
          accessedRouters = filterAsyncRouter(asyncRouter, roles)
        }
        commit('SET_ROUTERS', accessedRouters)
        resolve()
      })
    }
複製程式碼

從程式碼中可以看出,我這是隻區分了管理員角色admin和其他普通使用者(即非Aadmin兩種許可權)

該系列的實踐後續還將嘗試更多,將會一一撰帖成文,我也是個初學者,路漫漫而求索之。。。

相關文章