基本架构

一,权限层的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_users、change_user、delete_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_users、change_user、delete_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}