本文主要是本身在实际业务开发中的一些总结,写出来但愿与你们一块儿探讨。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函数。水平有限,其实也没有用的很深,只是基本解决了现有的问题。业务开发久了,可能以为没什么提高,可是在平常的开发中也是能够活学活用的,将一些编程的基础思想积极应用到开发中也许有意向不到的结果。这里写出来供你们参考,若是有更好的想法也欢迎一块儿讨论。