前端權(quán)限管理方案之精確到按鈕級別

這是產(chǎn)品提出的要求:

頁面上的每一個按鈕,都要可以通過角色權(quán)限來控制

??當(dāng)時的項(xiàng)目背景是一個零售系統(tǒng)的后臺管理,所以會涉及到運(yùn)營、廠家、管理員等等很多角色的使用,而其中許多數(shù)據(jù)是敏感的,例如銷量,單價,利潤等。前期的權(quán)限僅限于菜單級別的控制,也就是可以通過配置實(shí)現(xiàn)可以控制某個角色只顯示某些菜單,這也是比較常規(guī)的權(quán)限處理方案——沒權(quán)限就不讓你看那個頁面唄~

****舊的按鈕權(quán)限控制:****

//按鈕根據(jù)角色寫死是否有權(quán)限,靈活性很差,修改權(quán)限需要前端改代碼,而且哪個按鈕有權(quán)限純靠閱讀代碼識別
<button disabled={role !== "admin"}>刪除</button> //大致代碼,角色為admin按鈕才可用

??但目前的情況是菜單的控制在現(xiàn)有系統(tǒng)的背景下已經(jīng)略顯粗放了,比如有的人是可以看銷售頁面的,只是不允許他導(dǎo)出,又或者允許他新增一個商品,但是不允許他刪除,所以呢要求雖然有點(diǎn)高,但是這個需求無疑是合理的。做過類似系統(tǒng)的朋友都應(yīng)該了解,后管系統(tǒng)的列表類型頁面,往往是增刪改查集一體的,甚至還有導(dǎo)出、綁定、上傳之類的操作。另一個前提是,實(shí)現(xiàn)按鈕權(quán)限控制的同時之前菜單權(quán)限的控制也要保留支持。

****解決方案構(gòu)思:****

方案一,既然某些操作是不允許的,是否可以將操作歸類統(tǒng)一賦予角色權(quán)限呢,比如運(yùn)營A角色無刪除類權(quán)限,運(yùn)營B角色有新增類權(quán)限,類似來歸類實(shí)現(xiàn)管理。可落到實(shí)處,會發(fā)現(xiàn)操作很難歸類,刪除和修改其實(shí)是類似的,綁定解綁等操作更是無法準(zhǔn)確分類;更大的問題是,有的角色是可以的刪除A頁面數(shù)據(jù),但是不允許刪除B頁面數(shù)據(jù)的,而且這種方式靈活度也很低,比菜單好不到哪去,所以否掉。

方案二,摒棄按鈕分類思想,給每個按鈕賦予唯一code用于控制權(quán)限,管理角色權(quán)限直接勾選該角色是否激活某個code權(quán)限即可;擬定一個鑒權(quán)函數(shù),入?yún)?shù)為code,該函數(shù)放置于每個按鈕中,鑒權(quán)函數(shù)根據(jù)code是否在后端返回的該角色擁有code列表中,來判斷返回是否具有權(quán)限,具有很高的靈活性,并且菜單也可以通過加code來實(shí)現(xiàn)同樣效果,改動微小幾乎只用增加一個鑒權(quán)函數(shù)即可實(shí)現(xiàn)核心邏輯。

最終采用方案二,在實(shí)際研發(fā)中,還做了優(yōu)化:

1.將權(quán)限控制按層級分為模塊,菜單,按鈕3大層級,因?yàn)楫?dāng)整個模塊都沒有權(quán)限的時候,不必再判斷按鈕權(quán)限,提高性能,菜單亦如此。

2.code實(shí)際是用英文字符來表示,增強(qiáng)可讀性,例如設(shè)備菜單是deviceMenu,而不是無意義的id。

3.實(shí)際鑒權(quán)函數(shù)入?yún)槟K,菜單,按鈕3個參數(shù),更好理解也更加符合直覺,模塊下有多個菜單,菜單下有多個按鈕,也就是說幾乎每個添加按鈕都可以取名“add”,不必?fù)?dān)心重復(fù)。

4.將列表字段當(dāng)按鈕處理,甚至可以實(shí)現(xiàn)同一列表每個字段的權(quán)限控制,例如部分敏感價格字段顯示為**(當(dāng)然安全性不高)

5.后端只需返回當(dāng)前用戶角色擁有的全部模塊,菜單,按鈕code即可

具體實(shí)現(xiàn)核心代碼如下

// 給菜單路由增加code標(biāo)識,后續(xù)根據(jù)角色擁有菜單情況遍歷剔除無權(quán)限菜單即可
        {
            path: 'model',
            name: 'DeviceModelList',
            code: 'device_model',//  菜單僅在原路由增加code,改動很小
            meta: {
                title: '設(shè)備型號',
                icon: 'md-menu'
            },
            component: () => import('@/views/DeviceModelList')
        }
// 給按鈕增加函數(shù)鑒權(quán),此處是采用禁用點(diǎn)擊,也可以使用if直接不顯示
    <Button:disabled="!checkButtonPower('device','device_list','add')">添加設(shè)備</Button>
// 鑒權(quán)函數(shù),判斷模塊和菜單就不用傳第二,三個參數(shù)即可(當(dāng)時的代碼實(shí)在是不夠優(yōu)雅?。?    checkButtonPower(modelCode, menuCode, buttonCode) {
    let powerStatus = false
    //取出權(quán)限列表
    const isGetPower = localStorage.getItem('userPower')
    const powerList = isGetPower ? base64.decryptAsObj(isGetPower) : null
    for (const modes of powerList) {
        if (!!modes.menuCode && modes.menuCode == modelCode) {
            for (const menus of modes.childMenu) {
                if (!!menus.menuCode && menus.menuCode == menuCode) {
                    for (const buttons of menus.buttons) {
                        if (!!buttons.code && buttons.code == buttonCode) {
                            powerStatus = true
                        }
                    }
                }
            }
        }
    }
    return powerStatus
   },

至此,功能實(shí)現(xiàn),如有疑問歡迎留言
PS:后續(xù)實(shí)現(xiàn)后發(fā)現(xiàn)Vben-admin也是用的類似的思路實(shí)現(xiàn)了細(xì)粒度的權(quán)限管理,思路沒錯~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容