推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
prasanta
V2EX  ›  Python

一种新的 RESTful 权限设计讨论

  •  
  •   prasanta · Apr 12, 2017 · 6695 views
    This topic created in 3344 days ago, the information mentioned may be changed or developed.

    请求权限映射

    根据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. 能否将整个认证鉴权流程规范化?
    24 replies    2017-04-13 00:20:46 +08:00
    torbrowserbridge
        1
    torbrowserbridge  
       Apr 12, 2017
    并没觉得新在哪里。

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

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

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

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

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

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

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

    上述方法与所用语言无关。
    wc951
        21
    wc951  
       Apr 12, 2017 via Android
    没觉得新在哪啊, apache shiro 不就在干这事吗,不过那个是 java 的
    hantsy
        22
    hantsy  
       Apr 12, 2017
    @zhengxiaowai Patch 已经有相关的具体标准 JSON Patch 等,去修改 Entity 部分属性。

    https://tools.ietf.org/html/rfc6902

    之前我用到了 Spring Sync 支持 Patch 。

    https://spring.io/blog/2014/10/22/introducing-spring-sync

    下一代的 JAXRS 2.1 ( Java EE 8 标准)会加入官方的 Patch 支持(虽然自己实现不难)。
    ihuotui
        23
    ihuotui  
       Apr 12, 2017
    权限
    如果你是了解 spring mvc,权限验证可以放在 interceptor
    http->tomcat->interceptor(check user is login and auth resource)->biz_service
    restful 风格,感觉它只是给了一个指导,实际需要我们自己拓展.
    我建议使用 biz_group/biz_add or other 数据放在 post 中
    因为在复杂业务下,需要表达的含义远多于 crud,从可读代码上看
    honmaple
        24
    honmaple  
       Apr 13, 2017
    我是觉得作为中间件放到控制器之前好,首先代码侵入性较小,其次只需要单独维护一套权限系统就行,只要简单修改就可以用到其它系统中,权限的验证无非是验证 + 回调,我不认为会增加复杂性,当然,会造成额外的数据查询这是个问题
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5919 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 62ms · UTC 02:09 · PVG 10:09 · LAX 19:09 · JFK 22:09
    ♥ Do have faith in what you're doing.