通用权限管理

1,507 阅读4分钟
原文链接: www.aixiangfei.cn

基本架构

基本架构

一,权限层的2个基本概念

1,操作operation

操作是系统中预先规定好的需要被限制的一组API接口。比如,现在系统中有以下API接口:

GET /users
POST /users
DELETE /users/{id}
GET /categories
POST /categories
DELETE /categories/{id}
GET /articles
POST /articles
DELETE /articles/{id}

假如该系统中下面接口

GET /users
POST /users
DELETE /users
DELETE /categories

是比较重要的接口,而其余接口我认为不是很重要。那么我就定义如下3个操作

{
  "title": "查询用户", 
  "id": "query_users",
  "api": [
    {
      "uri": "/usrs",
      "method": "GET"
    }
  ]
},
{
  "title": "新增/删除用户",
  "id": "change_user",
  "api": [
    {
        "uri": "/users",
        "method": "POST"
    },
    {
        "uri": "/users/{oid}",
        "method": "DELETE"
    }
  ]
},
{
  "title": "删除分类",
  "id": "delete_category",
  "api": [
    {
        "uri": "/categories/{id}",
        "method": "DELETE"
    }
  ]
}

2,授权authorize
授权是一个动词。
现在我希望只允许id为32的用户拥有能进行上面3个操作,即:将上面3个操作授权给id等于32的这个用户,那么授权域中就会有如下数据:

{
    "operation_id": "query_users",
    "identities": [
      {
        "key": "user",
        "value": "32"
      }
    ],
    "auth": "allow",
    "priority": 1
},
{
    "operation_id": "change_user",
    "identities": [
      {
        "key": "user",
        "value": "32"
      }
    ],
    "auth": "allow",
    "priority": 1
},
{
    "operation_id": "delete_category",
    "identities": [
      {
        "key": "user",
        "value": "32"
      }
    ],
    "auth": "allow",
    "priority": 1
}

注:目前默认auth都传allow,priority都传1就行了,遇到复杂的权限系统再考虑。

过了段时间我希望让id为5的用户组能够进行删除分类这个操作,那么我就发送
POST /permissions/key/group/value/5

"opreation": "delete_category",
"auth": "allow",
"priority": 1

所以最终授权域中的数据就变成了这样的:

{
    "operation_id": "query_users",
    "identities": [
      {
        "key": "user",
        "value": "32"
      }
    ],
    "auth": "allow",
    "priority": 1
},
{
    "operation_id": "change_user",
    "identities": [
      {
        "key": "user",
        "value": "32"
      }
    ],
    "auth": "allow",
    "priority": 1
},
{
    "operation_id": "delete_category",
    "identities": [
      {
        "key": "user",
        "value": "32"
      },
      {
        "key": "group",
        "value": "5"
      }
    ],
    "auth": "allow",
    "priority": 1
}

那么当我访问这些接口的时候,权限层会得到当前用户的所有信息,然后再到授权域中去检查授权。举例:

  • 假如我的用户id是12,我访问POST /users接口的时候,权限层就会返回403错误。
  • 假如我的用户id是13,我所在的用户组id是5,我访问POST /users接口会返回403错误,而访问DELETE /categories/{id}就可以正常访问了
  • 假如我的用户id是32,那么我访问所有的接口时,权限层都不会返回403

二,后端

当一个系统接入权限层了之后,首先呢就是列出所有的API接口,然后找到比较重要的接口,定义好操作,权限层就会自动去做API的授权检测。

对于一个典型的系统来说,会有部分的API接口是没有经过权限层的,比如用户登录接口、公开给任何人一些公开数据接口等。

三,前端

前端需要做2件事情
1,菜单控制
假设系统界面如下所示:

- 用户管理   
     [新增]
     id: 1     name: 张三     sex: 男     [删除]
     id: 2     name: 李四     sex: 男     [删除]
- 分类管理
    [新增]
    id: 1      name: 分类1     [删除]   
    id: 2      name: 分类2     [删除]
- 文章管理
    [新增]
    id: 1      name: 文章1     [详情][删除]
    id: 2      name: 文章2     [详情][删除]

前后端需要先约定好所有的操作operations,即:前端应该知道当前系统中一共拥有3个操作:query_userschange_userdelete_category
所以前端先定义默认值:

var operations = [
  query_users = false,
  change_user = false,
  delete_category = false
];

然后
在菜单用户管理中设置display的值为display=operations.query_users
在用户管理的新增删除按钮处设置display的值为display=operations.change_user
在分类管理的删除按钮处设置display的值为display=operations.delete_category

那么当用户登录到系统之后,前端应该主动请求接口GET /users/{id},其中{id}是当前用户的id,接口除了返回当前用户的基本信息之外,还会额外的返回一个permissions数组,这个数组中列出了当前用户允许进行的所有操作

  • 假如当前用户id为32,那么permissions中应该有三项:query_userschange_userdelete_category。那么前端就将operations数组改成:
var operations = [
  query_users = true,
  change_user = true,
  delete_category = true
];

此时所有的菜单和按钮都会显示出来。

  • 假如当前用户id为13,用户组id为5,那么permissions中应该有一项:delete_category。那么前端就将operations数组改成:
var operations = [
  query_users = false,
  change_user = false,
  delete_category = true
];

此时菜单用户管理会被隐藏

2,授权方式1:将操作授予给对象
授权
接口提交方式:
POST /permissions

3,授权方式2:给对象授予操作权限
授权
接口提交方式:
POST /permissions/key/{key}/value/{value}