一种新的 RESTful 权限设计讨论

2017-04-12 10:40:14 +08:00
 prasanta

请求权限映射

根据RESTful的相关风格规范, 我们将请求映射为以下几种操作

GET     /users/                ----->  `list.users` 
GET     /users/:id/            ----->  `retrieve.users`
POST    /users/                ----->  `create.users`
PUT     /users/:id/password/   ----->  `replace.users`
PATCH   /users/:id/            ----->  `update.users`
DELETE  /users/:id/            ----->  `destroy.users`

权限控制器映射

如果后端以MVC模式进行开发, 那么我们可以映射如下控制器

`list.users`        ----->  list(users) 
`retrieve.users`    ----->  retrieve(user,id)  
`create.users`      ----->  create(users)       
`replace.users`     ----->  replace(users,id,field)   
`update.users`      ----->  update(users,id)           
`destroy.users`     ----->  destroy(users,id)           

鉴权流程

权限的管理采用传统的RBAC模式

  1. 身份验证,返回具体user或者anonymous,接下来我们把这一步返回的user都作为正常user
  2. 验证请求权限,即上述验证请求权限映射
  3. 验证资源存在性与所属权, 这里存在争议.
    • 如果放到控制器之前, 那么可能会出现格外数据库查询,同时会增加代码上的复杂性, 但是可以把所有鉴权过程放到一起.
    • 如果放到控制器中,鉴权过程分开了,由于不同的资源可能有不同的所属权判断标准,这样可以增加灵活性.

讨论点

  1. 资源存在性与所属权放到控制器里还是作为中间件放到控制器之前?
  2. 请求权限映射有哪些需要改进的地方?
  3. 能否将整个认证鉴权流程规范化?
6172 次点击
所在节点    Python
24 条回复
torbrowserbridge
2017-04-12 10:48:00 +08:00
并没觉得新在哪里。

我们的做法:功能权限前置,数据权限后置(对应你这里资源权限)。

现在想想,设计良好的系统也可以做到数据权限前置,而不会(明显)增加查询次数。比如,将数据权限中的查询结果透传给控制器。
prasanta
2017-04-12 10:55:21 +08:00
@torbrowserbridge 数据权限前置我发现的最大问题就是不同类型的资源可能有不同的判断方式,如果针对不同资源写不同方法,前置的意义也就不大了
torbrowserbridge
2017-04-12 10:56:52 +08:00
@prasanta 对,会丧失一定的灵活性。通常数据权限的判断逻辑非常复杂多样。所以要综合权衡一下利弊。
prasanta
2017-04-12 11:08:41 +08:00
@torbrowserbridge 市面上现在似乎没有鉴权规范化的项目
zhengxiaowai
2017-04-12 11:19:17 +08:00
1. RESTful 标准中 PATCH 的语义是 update/replace , PUT 的语义是 update/modify 。我认为用一个 PUT 方法就可以,没必要多一个 PATCH ,少一接口,多一份放心。很多 API 都没有实现 PATCH 方法,都是用 PUT 实现的。

2. 我觉得放在控制器中比较好。一般来说中间件是一种通用的解决方案,权限控制又是一种十分复杂而且多变的。作为一个中间件,没有任何复用性可言。
weaming
2017-04-12 11:54:33 +08:00
不是 PUT 添加, POST 修改吗
scofieldpeng
2017-04-12 12:22:20 +08:00
@weaming 童鞋,你确定你看的不是假文档?
otakustay
2017-04-12 12:23:36 +08:00
@weaming POST 添加, PUT 修改, PUT 的 URL 指向**唯一**资源

@zhengxiaowai PATCH 可以是 partial entity , PUT 不行,所以这里还是有区别的
weaming
2017-04-12 12:35:16 +08:00
ihuotui
2017-04-12 12:53:49 +08:00
其实这样写 性能低,有测试过,在解析 url 时候
otakustay
2017-04-12 12:59:15 +08:00
@weaming yes ,只要你知道资源的唯一 URL 就无论添加还是修改都行,但如果只知道一个 collection 的 URL 就不行
prasanta
2017-04-12 16:51:08 +08:00
@ihuotui 也就是将权限验证绑定到控制器里效率更高?
ihuotui
2017-04-12 17:01:59 +08:00
@prasanta 就是单单测试 url 性能,{id}get 和 get?id=xx
这两种比较。权限可以在 filter 或者 interseter 里面判断。反正都是 具体功能前的,而且最佳就是加上权限缓存。
ihuotui
2017-04-12 17:03:29 +08:00
反正我不用 resetful 规范,因为业务多了就不优雅了。
kenshinhu
2017-04-12 17:03:38 +08:00
话说 PATCH 好像不支持 formdata 吧?有图片上传的操作这个的话就比较麻烦了
prasanta
2017-04-12 17:33:34 +08:00
@kenshinhu 文件上传通常是统一做成单独的接口,以 Post 方式上传至 oss 或者其它地方,获取到返回的文件信息后再用于其它接口
prasanta
2017-04-12 17:34:38 +08:00
@ihuotui 可以说一下你现在使用的规范吗
justfly
2017-04-12 17:42:06 +08:00
最好设计上保持鉴权逻辑的通用和统一 ,然后鉴权前置。

至于所说的多一次数据库查询问题,可以把鉴权时查询到的数据放到一个当前请求的 context 中,业务逻辑如有需要,可以直接使用这个 context 中的数据,请求结束数据根据 context 一起销毁。
kenshinhu
2017-04-12 17:59:35 +08:00
@prasanta 这样会不会增加客户端的工作?这样做法 客户端所有涉及文件 的都 得先上转 oss 再把回来的信息 post 到服务器上

之前我也有想过这个方式 ,但好像会增加客户端的工作量,之后就没有这样做了

给写入方法都 是用 POST + formdata 实现
hantsy
2017-04-12 19:03:32 +08:00
1. 使用用 OAuth/OpenID 或者 JWT 时,返回的 Token 中都可以添加一个 scopes ,在用户登录时取得该用户所有的权限。与服务器交互一般都是 Stateless 方式去请求 API , Header 加上 Token 。
2. 服务器端解密 Token , 可以得到该用户分配的所有权限。直接对照检测 API 权限就行了。

上述方法与所用语言无关。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/354273

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX