Common Access System Design
最近在优化自己写的APPsite框架,其中一直以来没有妥善解决的权限模块可能是后面拓展出去的比较大的障碍。所以着手重写这个模块。 在现有的框架中ACCESS模块分为两大部分: 系统权限、单位权限两个。
系统权限主要用于验证系统功能是否可以执行。 主要支持了Token作用域验证功能,可以设置有效期、作用域、以及可执行次数。 ACCESS和密码验证不同,并不解决加密解密问题,只是负责一个权限的授予、验证、撤销的功能。
代码语言:javascript复制# 例1 手机改密码的流程: 作用域为 resetPassword
用户.发起请求 ->
权限系统.开始流程 ->
用户.提交验证 ->
权限系统.验证(通过/拒绝)并授权(设置有效期) ->
使用权限(一段时间有效 或 一次性有效)
单位权限类似于虚拟物品的所有权。支持以用户为单位的权限授权。 目前仅支持一种状态即 拥有( 可以访问、读取 ) 而写、删的权限仍然只归属于系统。
代码语言:javascript复制# 例2 虚拟商品包年授权:
用户.发起购买 -> ... -> 支付验证成功 ->
权限系统.添加授权(设置有效期) ->
用户.拥有权限
----
客户端.查询授权 ->
权限系统.验证(通过|拒绝)并返回内容|错误 ->
客户端.接收反馈 ->
用户.使用权限(获取内容等)
就现有的系统来说,目前在分层次系统权限授权的部分几乎没有支持,现在的实际开发中基本上是以 用户组 程序手动检测 的方式来实现内部控制。这样用户组权限的管理是不开放的、维护成本也很高、每次新增功能的时候 都需要做对应的代码内部控制,总体来说不灵活。 单位权限的部分没有做到真正的内容归属、只有内容读取的能力,这样是不能支持类似于微博这样的应用。另外内容加密的功能也没有从架构的层面解决,需要从底层得到支持。
那么接下来开始架构和功能设计。
基础的权限模型基于RBAC的基于角色访问的权限设计。 同样,系统功能权限和单位权限仍然保持在两个子模块中。同时还需要一个验证模块来支持外部接口。所以这里设计三个子模块
代码语言:javascript复制ACCESS
- operation // 系统权限
- permission // 单位权限
- verify // 验证支持
系统权限的部分 参考RBAC模型 我们还需要一个角色的模块来配合,比较具体的做法是
代码语言:javascript复制用户-角色 多对多绑定,角色-权限 多对多绑定
我这里使用的是Group 本质和Role是一样的,名字不同
User | Group | AccessOperation | AccessPermission | AccessVerify | Relation |
---|---|---|---|---|---|
userid | groupid | operation | userid | origin | itemid |
groupid | character | scope | itemid | scope | itemtype |
level | expire | itemtype | code | targetid | |
areaid | status | info | expire | targettype | |
... | expire | ... |
relation是通用关系绑定表 不仅限于用户绑定用户组,可以同时处理用户组和权限绑定。 在检测用户权限的时候需要合并 User,Group,AccessOperation,Relation四张表 查询出用户做拥有的所有权限 ( 也可以先在REDIS服务器缓存各个用户组所拥有的权限,因为用户组本身的数量并不会很大,所以此方案非常行得通 ) 之后在函数内部或是初始化时 请求ACCESS系统进行对应权限的认证。
具体的操作中应当一次性取出所有权限数据放置在用户对象中或Redis服务器,避免每一次都去请求数据库服务器。造成io堵塞。
取出的MySQL语句思路是:
代码语言:javascript复制SELECT * FROM AccessOperation LEFT JOIN Relation ON AccessOperation.id = Relation.targetid WHERE AccessOperation.status = 0 AND AccessOperation.expire > {$now} AND Relation.targettype = 'AccessOperation' AND Relation.itemtype = 'Group' AND Relation.itemid IN (
SELECT groupid FROM Group .... # 这里取出用户所拥有的的用户组
)
接下来的工作就比较简单了,这里只给出结构 解释一下这里为什么要多一个scope作用域,主要是为了拓展方便。 这里 可以将 operation * scope 相当于我们拥有了二维的权限管理。 例如 用户修改内容,我们支持两个scope 一个是创作者 owner, 一个是管理者 manager 这样我们就不需要写很长的 OwnerEditContent, ManagerEditContent这样的方式。
代码语言:javascript复制class ACCESS{
private $userid;
private $operations; # 操作权限数据
private $permissions; # 所属权数据
private $tokens; # 访问令牌
# 基于userid来实例化权限管理 游客默认无权限
function _construct( string $userid = NULL, string $token = NULL ){ }
/* 权限 */
# 检查权限
public function can( string $operation, string $scope = 'common' ){ }
# 取消权限
public function ban( string $operation, string $scope = 'common' ){ }
# 授予权限
public function grant( string $operation, string $scope = 'common', int $duration ){ }
/* 验证 */
# 生成令牌
public function add( string $scope = 'access', int $duration ){ }
# 更新令牌
public function update( string $scope = 'access', int $duration ){ }
# 查验令牌
private function check( ){ }
# 验证流程开始
public static function start( string $origin, string $scope, int $duration ){ }
# 验证安全防护
public static function gruad( string $origin, string $scope ){ }
# 验证查验
public static function verify( string $origin, string $scope, string $code ){ }
/* 所属权 */
# 检查
public function have( string $itemid, string $itemtype ){ }
# 给予
public function give( string $itemid, string $itemtype, int $duration ){ }
# 丢弃
public function drop( string $itemid, string $itemtype ){ }
# 查看携带信息
public function info( string $itemid, string $itemtype ){ }
/* 其他 */
# 清理无效数据
public function clear( string $mode ){ }
}
一些参考: 权限系统设计模型分析(DAC,MAC,RBAC,ABAC) "推荐"