本文主要是本身在實際業務開發中的一些總結,寫出來但願與你們一塊兒探討。javascript
首先介紹一下業務背景:前端
綜上,在不一樣部署平臺下,不一樣級別(角色)的人員在同一個房間裏,他們所看到的界面和能使用的功能是不同的。並且一個角色受限於部署平臺和主管理員所購買的平臺服務,或者隨着主管理員關閉/開放某些功能,看到的界面也會不同。java
因此咱們須要作一套權限管理系統來綜合處理這些信息(平臺、帳戶、角色),保證各角色看到不一樣的界面。能夠看到咱們這裏說的權限已經不只限於簡單的角色權限,還包括角色之上的平臺和帳戶管理員的限制。git
由於最後的權限取決於所登陸的帳戶,因此在開發中,咱們將權限和帳戶信息放到了一塊兒,統稱爲metaConfig,即帳戶元信息,包含帳戶名字、角色等基本信息,所屬主帳號,具體角色信息,角色權限等,它將決定最終的界面顯示。github
咱們使用React和Redux來開發,metaConfig對象能夠直接存在Redux中進行管理。編程
在咱們的系統中,metaConfig的處理是放在reducer中的,會有一個默認的defaultMetaConfig,經過reducer生成最後的metaConfig。權限管理最關鍵的就是如何生成各個角色對應的metaConfig,總結起來就是:redux
metaConfig=f(defaultMetaConfig)
把複雜問題拆分紅簡單問題
是開發中的一個重要手段。這裏咱們能夠經過分層處理的方式,將權限管理拆分紅多個層級,每層對應一個處理模塊。這樣一個大的權限處理過程就變成解決每一個層級的權限處理。微信
咱們先來看看系統權限管理受到哪些因素影響:部署方式(外網內網),對接平臺,帳戶管理員購買的服務和開啓/關閉的功能,帳戶級角色(帳戶管理員、子管理員),房間角色(管理員、講師、助手、嘉賓等)。函數式編程
咱們把每一層抽象成一個處理器,稱爲parser,簡單區分以後能夠分爲:deployParser(部署方式),platformParser(平臺),accountParser(帳戶),roleParser(角色)。函數
UNIX中有一個pipeline(管道)的概念,一個程序的輸出直接成爲下一個程序的輸入。結合到咱們的業務,能夠輸入一個默認的metaConfig,而後依次經過各個層級的parser函數,最終輸出一個metaConfig。
js中pipeline的簡單實現以下,compose函數的處理順序是反着的,能夠查看Redux中 compose的實現。
// 管道函數 const pipe = (...funcs) => { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => b(a(...args))) }
把咱們抽象好的parser丟到pipe函數中,結果以下:
metaConfig = { ...pipe( deployParser, platformParser, accountParser.createAccountParser(account), roleParser, )(defaultMetaConfig) }
注意accountParser.createAccountParser(account)這行,咱們下面一節分析。
這樣咱們經過管道函數將權限的處理拆分紅多個層級,每一個層級會操做metaConfig內對應的屬性,是否是簡單明瞭。由於是函數式的處理,能夠直接放在reducer中計算出metaConfig而後保存到Redux中。
這裏處理權限(不只限於權限,還包括一些帳戶基礎信息)的操做分爲兩種狀況:
// 須要重置的數據 newConfig.isSuperManager = false newConfig.isAdmin = true newConfig.name = manager.name
accountParser = metaConfig => ({ ...metaConfig, // 在accountParser中進行merge操做,合併從上一層傳來的metaConfig,這樣的權限處理可能有多處 somePermission: mergeSomePermission(metaConfig.somePermission), ... }) // merge函數內進行具體的&操做, mergeSomePermission = prePermission => { // 當前層級沒有使用短信的權限 prePermission.canUseMsg = prePermission & false, // 每一個merge函數能夠處理多個權限點,這裏只寫了一個 ... }
經過上面的分層能夠從大的方向上去解決權限問題,可是業務中的權限是動態的,不斷擴展的,如何處理業務迭代中產生的這些問題?好比上面例子中mergeSomePermission的短信權限是限定死的爲false,可是可能有的角色有這個權限,而其餘角色沒有這個權限。在account這層一個簡單的parser沒法處理不一樣帳戶間之間的差別, 並且不一樣級別帳戶須要處理的權限範圍可能也不同,同一層級還須要不一樣的處理函數
,用account做爲參數,來細化各個處理器。
咱們可能須要下面的代碼,在帳戶權限處理中加入不一樣帳戶的處理器:
accountParser = (account, metaConfig) => { cosnt { superManager = null, normalManager = null } = account // 分別處理superManager和normalManager的權限 let newConfig = superManagerParser(superManager, metaConfig) newConfig = normalManagerParser(normalManager, newConfig) return newConfig } superManagerParser = (superManager = null , metaConfig) => // 若是是主管理員則處理 superManager ? ({ ...metaConfig, // 根據superManager信息處理 somePermission: mergeSomePermission(superManager, metaConfig.somePermission), // 主管理員功能須要多處理一些權限 someSystemPermission: mergeSomeSystemPermission(superManager, metaConfig.somePermission) }) : metaConfig normalManagerParser = (normalManager, metaConfig) => normalManager ? ({ ...metaConfig, // 根據normalManager信息處理 somePermission: mergeSomePermission(normalManager, metaConfig.somePermission) }) : metaConfig
從以前的管道處理中咱們已經看到一些函數式編程的影子,咱們能夠繼續使用一些函數式的方法來加工上面的函數。管道處理中的accountParser.createAccountParser(account)就是處理這個問題的。
// 函數柯里化 createSuperManagerParser = (superManager = null) => metaConfig => // 若是是主管理員則處理 superManager ? ({ ...metaConfig, // 主管理員功能須要多處理一些權限 someSystemPermission: mergeSomeSystemPermission(superManager, metaCofig.somePermission) somePermission: mergeSomePermission(superManager, metaCofig.somePermission) }) : metaConfig // 函數柯里化 createNormalManagerParser = (normalManager = null) => metaConfig => normalManager ? ({ ...metaConfig, somePermission: mergeSomePermission(normalManager, metaCofig.somePermission) }) : metaConfig // 合併成一個帳戶級的parser const createAccountParser = account => { const { normalManger = null, super_manager = null } = account || {} return pipe( createSuperManagerParser(super_manager), createNormalManagerParser(normalManger), ) }
咱們使用柯里化將兩個parser函數處理後,可使它們都接受metaCofig做爲參數,並繼續使用一個管道組合成帳戶級別的accountParser,它的參數仍是metaConfig。這樣咱們在account這層用柯里化和組合使得parser也能夠用管道進行再次分層處理。
一樣的操做也能夠應用在角色處理器roleParser中。應用RBAC權限管理,一個角色對應一個parser,使用柯里化和pipe合成一個大的roleParser。
介紹到這裏,本文所要說的函數式編程在前端權限管理中的應用就差很少了。
大體有如下幾點緣由:
本文主要介紹了函數式編程(管道、柯里化、組合)在前端權限管理中的應用,經過分層解耦,多級分層將複雜的權限管理拆解成細粒度的parser函數。水平有限,其實也沒有用的很深,只是基本解決了現有的問題。業務開發久了,可能以爲沒什麼提高,可是在平常的開發中也是能夠活學活用的,將一些編程的基礎思想積極應用到開發中也許有意向不到的結果。這裏寫出來供你們參考,若是有更好的想法也歡迎一塊兒討論。