前端面試必備——權限控制

clipboard.png

0.前言

記得當年面試的時候,面試官問我,前端怎麼作權限控制,咱也不太會這個,只能尷尬回答道:「都是老大搭的架子,我只負責寫業務模塊代碼」,😭😭😭。
現在本身也作了不少項目了,以爲有必有對前端權限控制作一個總結。前端

前端權限控制一直是前端必須掌握的一個知識點,通常來講稍微正規一點的後臺系統確定有權限控制。固然仍是那句老話,前端原本就是不安全的,真正的安全仍是須要後端兄弟去把關,因此後端也必須按作權限控制!咱們前端的權限校驗主要的目的是過濾不應有的請求和操做,減小服務端壓力。vue

我我的認爲前端權限控制應該分爲四個方面,接口權限、按鈕權限,頁面權限,路由權限,下面就分四個部分探討下權限控制怎麼作node

1.接口權限

原則

接口權限最簡單,目前通常採用jwt的形式來驗證,沒有經過的話通常返回401 Authentication Required, 返回登陸頁從新登陸
登陸完拿到Token,將token存起來(cookie或者ssessionStorage),每次登陸的時候頭部攜帶token就好了(axios請求攔截器實現)。ios

僞碼實現

const {token} = login()
cookie.set('token',token)
axios.interceptors.request.use(config => {
        config.headers['token'] = cookie.get('token')
    return config
})
axios.interceptors.response.use(res=>{},{response}=>{
    if (response.data.code === 40099 || response.data.code === 40098) { //token過時或者錯誤
      router.push('/login')
    }
})

2.按鈕權限

原則

一個頁面會有新增,刪除,編輯等等按鈕。不一樣用戶應該是有不一樣操做權限的。
咱們不妨定義權限碼 0:不可見 1:不可編輯 2:可編輯
咱們提早和後端約定好按鈕的名字,後端會返回一個按鈕權限列表。而後咱們根據權限列表使用v-if指令或者 綁定disabled屬性達到相應權限效果。
固然更好的最好是本身寫一個自定義權限指令,實質就是根據相應權限操做dom面試

僞碼實現

好比概覽頁面的編輯按鈕 名字先和後端定義好叫作overview-editvuex

// overviwe.vue  overview是概覽頁面的路由名
...
<button v-auth='edit'>
...
//util.js 全局註冊自定義指令

Vue.directive('auth', {
    inserted: function (el, binding, vnode) {
        const optName = binding.arg
        const authName = `${routeName}-${optName}`     //這裏根據路由名和操做類型拼出按鈕名 overview-edit
        const btnAuthList = store.state.auth.btnAuthList
        if (btnAuthList[authName]===0) { // 按鈕權限爲0則移除dom
            el.parentNode.removeChild(el)
        } else if (btnAuthList[authName]===1) { // 按鈕權限爲1則禁用按鈕
            vnode.componentInstance.disabled = true
        }
    }
})

// 登陸的時候接受按鈕權限並存在vuex裏面
const {btnAuthList} = login()
vuex.state.btnAuthList = btnAuthList

3.頁面權限(菜單權限)

我的認爲頁面權限實際上就是菜單權限,若是說咱們沒有去某個頁面的導航菜單,實際上就是沒有去那個頁面的權限了,因此說頁面權限的實際就是菜單權限。數據庫

原則

一句話,獲取菜單權限列表,動態遞歸生成菜單
這個菜單權限列表能夠是後臺直接返回你的,也能夠是你註冊路由的時候寫在meta裏面的菜單信息,後臺返回路由權限,你根據meta信息動態算出的菜單權限。
至於菜單確定是根據菜單權限遞歸生成的element-ui

僞碼實現

//若是是定義在route信息裏面會是這種樣子
//咱們能夠根據後端返回的路由權限結合meta算出菜單權限
{
name:xxx
path:xxx
meta: {
        role: [xxx,xxx,xxx] //哪些角色有資格
        MenuIcon: 'xxxx'  //菜單圖標
        MenuTitle: 'xxx' //菜單名
    }
}


//固然也能夠麻煩後臺直接生成菜單權限返回來
const {menuList} = login()
//存vuex裏
vuex.state.menuList = menuList
//在側邊欄或者頂部菜單組件裏動態生成菜單
//這裏基本都是用的UI庫,好比element-ui的NavMenu來實現的,你們有興趣能夠本身看文檔,固然也能夠本身遞歸實現,不難
<navMenu/ :menuList=menuList>

4.路由權限

上面的菜單權限雖然作到能看不見菜單,可是我能夠經過直接輸入url的方式去沒有權限的頁面呀,這種狀況須要靠咱們的路由權限來阻止。axios

原則

這裏有兩個方案
第一種,也是我目前項目用的,先註冊好全部的路由,而後獲取有資格訪問的路由權限列表,最後直接經過Router.beforeEach來判斷,每次跳路由的時候判斷是否在權限列表裏,在的話就放行,不在就提示權限不夠
優勢:簡單暴力,不會跳到404頁面(由於去的路由能在路由規則裏找到)
缺點:因爲初始化了全部路由,運行的時候會掛載沒必要要的路由(?有待考究)
第二種,先只註冊基本路由,而後獲取路由權限列表,而後藉助route.add() API根據權限列表將有權限的路由動態註冊到路由規則上
優缺點與第一種正好相反segmentfault

僞碼實現

這裏只寫第一種方案,第二種你們自行google

const {routeAuthList} = login()
cosnt whiteList = ['/login','/','/404']
//合併生成總路由
whiteList = whiteList.contact(routeAuthList)
//存vuex
vuex.state.whiteList = whiteList
//路由守衛判斷
router.beforeEach((to, from, next) => {
    //權限校驗
    let pass = whiteList.inclue(to);
    if(!pass){
        return console.log('無權訪問');
    }
    next();
});

5.討論

後端返回什麼

這個我以爲實際沒有定論,相關的文章也讀了許多,什麼作法都有,仍是須要結合實際業務。
好比
1.按鈕權限特別少的,那麼後端不用返回按鈕權限,直接前端生成鈕權限就行。甚至不用使用自定義指定,直接v-if,disable就行
2.權限頁面特別多,次級路由也特別多,那麼也能夠前端這邊生成路由權限,由於若是後端返的話,每次定義一個次級頁面都得讓後端在數據庫加一條數據,太麻煩人了,不方便
3.後端也不是說非得返回權限路由列表的,像我目前的項目就是返回的菜單列表,而後我根據菜單列表名手動算出權限列表。其實都同樣,返回權限列表也是根據權限列表裏面的meta算出菜單列表,有毛區別?

緩存什麼

關於緩存,你們能夠看我這篇文章緩存
獲取的我的信息(包括權限列表)該不應緩存到ssessionStorage裏面?我看不少人的文章都是隻緩存token,每次刷新都是從新拉取信息。
我的認爲這樣作意義不大,緩存的目的就是爲了減小請求,優化交互。存在當前頁籤基本能保證同一時間你就是你。再說防君子不防小人,至於真的是小人,篡改ssessionStorage數據,咱不是還有後臺兄弟的校驗嗎,怕個卵。

6.總結

總結了前端全部的權限控制,並給出了相應的僞碼實現,但願能給你們帶來應該的幫助

相關文章
相關標籤/搜索