Start
記錄寫(xiě)后臺(tái)管理系統(tǒng)時(shí)的一些想法和組件的二次封裝,項(xiàng)目初期參考的是花褲衩大神的vue-element-admin,后期根據(jù)業(yè)務(wù)進(jìn)行了一些修改。
登錄
登錄流程的思路我們先屢清楚:
- 用戶在登錄頁(yè)輸入賬號(hào)密碼,將賬號(hào)密碼發(fā)送請(qǐng)求給后端
- 將賬號(hào)密碼發(fā)送請(qǐng)求給后端的方法寫(xiě)在
vuex里便于全局token的存取,而前端登錄方法里只需要關(guān)注登錄的結(jié)果,并根據(jù)結(jié)果跳轉(zhuǎn)頁(yè)面或提示錯(cuò)誤,這樣代碼結(jié)構(gòu)會(huì)清晰。
<!-- action: --> Login ({commit}, userInfo) { const { username, password } = userInfo return new Promise((resolve, reject) => { login({ username: username.trim(), password: password }) .then(res => { if (res.event !== 0) { reject(res) } Vue.ls.set(ACCESS_TOKEN, res.data.token, 12 * 60 * 60 * 1000) commit('SET_TOKEN', res.data.token) resolve() }) .catch ((error) => { reject(error) }) }) }<!-- Login頁(yè)面: --> import { mapActions } from 'vuex' methods: { ...mapActions(['Login']), handleLogin () { this.$refs.loginForm.validate(valid => { if (valid) { this.loading = true this.Login(this.loginForm) .then(() => { this.$router.push({ path: this.redirect || '/' }).catch(err => {}) this.loading = false }).catch((err) => { this.$message.error(err.message); this.loading = false }) } else { console.log('error submit!!') return false } }) } } - 將賬號(hào)密碼發(fā)送請(qǐng)求給后端的方法寫(xiě)在
- 后端驗(yàn)證一下用戶的賬號(hào)和密碼的信息,如果符合就發(fā)一個(gè)token返回給客戶端,如果不符合就不發(fā)送token,返回驗(yàn)證錯(cuò)誤信息。
- 如果登錄成功,客戶端將
token存在localStorage里,之后要請(qǐng)求其他資源的時(shí)候,在請(qǐng)求頭里帶上這個(gè)token。-
service/http.js中全局請(qǐng)求攔截器中:config.headers['token'] = token。
-
- 后端收到請(qǐng)求信息,先驗(yàn)證下token是否有效,有效則下發(fā)請(qǐng)求的資源,無(wú)效則返回驗(yàn)證錯(cuò)誤。
獲取用戶信息
登錄成功之后,在全局路由鉤子router.beforeEach中攔截路由,判斷如果有token,就去獲取用戶信息
<!-- router.beforeEach -->
if (Vue.ls.get(ACCESS_TOKEN)) {
store.dispatch('GetInfo')
.then((infoRes) => {
const roles = res.data.role;
next()
})
}
權(quán)限
權(quán)限控制是很常見(jiàn)的需求,我們的業(yè)務(wù)要求控制到按鈕級(jí)別。
頁(yè)面級(jí)權(quán)限的實(shí)現(xiàn)方式是通過(guò)獲取當(dāng)前用戶的權(quán)限去對(duì)比路由表,生成當(dāng)前用戶具有權(quán)限可訪問(wèn)的路由表,通過(guò)
router.addRouters掛載到router上。
具體步驟如下:
- 判斷是否有
token,如果沒(méi)有就去登錄,有就第二步。 - 獲取用戶信息
store.dispatch('GetInfo')。 - 獲取信息成功之后,調(diào)用
store.dispatch('GenerateRoutes'),這個(gè)方法里會(huì)調(diào)用/router/index.js里的generatorDynamicRouter方法,并返回一個(gè)根據(jù)用戶信息構(gòu)建好權(quán)限的路由結(jié)構(gòu)。(generatorDynamicRouter方法里將后臺(tái)返回的一個(gè)平級(jí)的menu信息,通過(guò)遞歸的方式生成層級(jí)結(jié)構(gòu),再遞歸生成層級(jí)路由) - 將構(gòu)建的路由結(jié)構(gòu)信息利用
Vue-Router提供的動(dòng)態(tài)增加路由方法router.addRoutes加入到路由表中。 - 加入路由表后將頁(yè)面跳轉(zhuǎn)到用戶原始要訪問(wèn)的頁(yè)面,如果沒(méi)有
redirect則進(jìn)入默認(rèn)頁(yè)面。
我們把
登錄和獲取用戶信息分成了兩個(gè)接口,原因是當(dāng)用戶刷新頁(yè)面時(shí),可以根據(jù)登錄時(shí)獲取到的token去獲取用戶信息,避免了刷新還要調(diào)用登錄接口。
整體流程可以看這個(gè)圖:

前端控制權(quán)限
舊版本后臺(tái)的路由表是后端同學(xué)根據(jù)權(quán)限生成的,這使得前端小伙伴每開(kāi)發(fā)一個(gè)頁(yè)面就需要讓后端同學(xué)配一下路由和權(quán)限,光聽(tīng)著就開(kāi)始皺眉了???♀?。
于是我們采用了在前端頁(yè)面配置路由和權(quán)限,之后將這份路由表存到后端。
權(quán)限/菜單:

權(quán)限/角色:

一角色對(duì)應(yīng)多權(quán)限,一用戶對(duì)應(yīng)多角色
當(dāng)用戶登錄后得到
roles,前端根據(jù) roles 去向后端請(qǐng)求可訪問(wèn)的路由表,從而動(dòng)態(tài)生成可訪問(wèn)頁(yè)面,之后就是router.addRoutes動(dòng)態(tài)掛載到router上,和原來(lái)是相同的。
按鈕級(jí)權(quán)限
在配置菜單權(quán)限頁(yè)面也可以添加配置按鈕的權(quán)限,登錄之后的 store.dispatch('GetInfo') 中能拿到對(duì)應(yīng)權(quán)限的按鈕,并存儲(chǔ)在 vuex 中。
判斷按鈕是否展示是寫(xiě)了一個(gè)公用方法 checkPermission ,沒(méi)有用指令是因?yàn)闊o(wú)法適用于所有組件。
將提前設(shè)置好的 唯一鍵 傳入方法,就可以從vuex里 store.getters.buttons 拿到所有按鈕權(quán)限,對(duì)比后返回 true 或 false,來(lái)控制按鈕的展示。
<!-- 引入方法 -->
import { checkPermission } from '@/utils/permissions'
<!-- data中定義變量 -->
addEnable: checkPermission('system:role:add')
<!-- v-if判斷 -->
<el-button v-if="addEnable">添加角色</el-button>
最后
代碼地址戳這里哈~
附圖:

