RESTful API 怎么实现用户权限控制? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
JerryC
V2EX    程序员

RESTful API 怎么实现用户权限控制?

  •  
  •   JerryC 2015-03-29 21:48:18 +08:00 13444 次点击
    这是一个创建于 3924 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原文链接:简书

    前言

    有人说,每个人都是平等的;
    也有人说,人生来就是不平等的;
    在人类社会中,并没有绝对的公平,
    一件事,并不是所有人都能去做;
    一样物,并不是所有人都能够拥有。
    每个人都有自己的角色,每种角色都有对某种资源的一定权利,或许是拥有,或许只能是远观而不可亵玩。
    把这种人类社会中如此抽象的事实,提取出来,然后写成程序,还原本质的工作,就是我们程序员该做的事了。
    有了一个这么有范儿的开头,下面便来谈谈基于RESTful,如何实现不同的人不同的角色对于不同的资源不同的操作的权限控制。

    RESTful简述

    本文是基于RESTful描述的,需要你对这个有初步的了解。
    RESTful是什么?
    Representational State Transfer,简称REST,是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。
    REST比较重要的点是资源状态转换
    所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。
    "状态转换",则是把对应的HTTP协议里面,四个表示操作方式的动词分别对应四种基本操作:
    1. GET,用来浏览(browse)资源
    2. POST,用来新建(create)资源
    3. PUT,用来更新(update)资源
    4. DELETE,用来删除(delete)资源。

    RESTful CURD

    资源的分类及操作

    清楚了资源的概念,然后再来对资源进行一下分类,我把资源分为下面三类:
    1. 私人资源 (Personal Source)
    2. 角色资源 (Roles Source)
    3. 公共资源 (Public Source)

    Sources

    "私人资源":是属于某一个用户所有的资源,只有用户本人才能操作,其他用户不能操作。例如用户的个人信息、订单、收货地址等等。
    "角色资源":与私人资源不同,角色资源范畴更大,一个角色可以对应多个人,也就是一群人。如果给某角色分配了权限,那么只有身为该角色的用户才能拥有这些权限。例如系统资源只能够管理员操作,一般用户不能操作。
    "公共资源":所有人无论角色都能够访问并操作的资源。

    而对资源的操作,无非就是分为四种:
    1. 浏览 (browse)

    2. 新增 (create)
    3. 更新 (update)
    4. 删除 (delete)

    角色、用户、权限之间的关系

    角色和用户的概念,自不用多说,大家都懂,但是权限的概念需要提一提。
    "权限",就是资源与操作的一套组合,例如"增加用户"是一种权限,"删除用户"是一种权限,所以对于一种资源所对应的权限有且只有四种。

    Permissions

    角色用户的关系:一个角色对应一群用户,一个用户也可以扮演多个角色,所以它们是多对多的关系。
    角色权限的关系:一个角色拥有一堆权限,一个权限却只能属于一个角色,所以它们是一(角色)对多(权限)的关系
    权限用户的关系:由于一个用户可以扮演多个角色,一个角色拥有多个权限,所以用户与权限是间接的多对多关系。

    Relations

    需要注意两种特别情况:
    1. 私人资源与用户的关系,一种私人资源对应的四种权限只能属于一个用户,所以这种情况下,用户和权限是一(用户)对多(权限)的关系。
    2. 超级管理员的角色,这个角色是神一般的存在,能无视一切阻碍,对所有资源拥有绝对权限,甭管你是私人资源还是角色资源。

    数据库表的设计

    角色、用户、权限的模型应该怎么样设计,才能满足它们之间的关系?

    Models

    对上图的一些关键字段进行说明:

    Source
    • name: 资源的名称,也就是其他模型的名称,例如:user、role等等。
    • identity: 资源的唯一标识,可以像uuid,shortid这些字符串,也可以是model的名称。
    • permissions : 一种资源对应有四种权限,分别对这种资源的browse、create、update、delete
    Permission
    • source : 该权限对应的资源,也就是Source的某一条记录的唯一标识
    • action :对应资源的操作,只能是browse、create、update、delete四个之一
    • relation:用来标记该权限是属于私人的,还是角色的,用于OwnerPolicy检测
    • roles: 拥有该权限的角色
    Role
    • users : 角色所对应的用户群,一个角色可以对应多个用户
    • permissions: 权限列表,一个角色拥有多项权利
    User
    • createBy : 该记录的拥有者,在user标里,一般等于该记录的唯一标识,这一属性用于OwnerPolicy的检测,其他私有资源的模型设计,也需要加上这一字段来标识资源的拥有者。
    • roles : 用户所拥有的角色

    策略/过滤器

    在sails下称为策略(Policy),在java SSH下称为过滤器(Filter),无论名称如何,他们工作原理是大同小异的,主要是在一条HTTP请求访问一个Controller下的action之前进行检测。所以在这一层,我们可以自定义一些策略/过滤器来实现权限控制。
    为行文方便,下面姑且允许我使用策略这一词。

    *策略 (Policy) *

    下面排版顺序对应Policy的运行顺序

    1. SessionAuthPolicy
      检测用户是否已经登录,用户登录是进行下面检测的前提。
    2. SourcePolicy
      检测访问的资源是否存在,主要检测Source表的记录
    3. PermissionPolicy
      检测该用户所属的角色,是否有对所访问资源进行对应操作的权限。
    4. OwnerPolicy
      如果所访问的资源属于私人资源,则检测当前用户是否该资源的拥有者。

    如果通过所有policy的检测,则把请求转发到目标action。

    Policies

    Sails下的权限控制实现

    在Sails下,有一个很方便的套件sails-permissions,集成了一套权限管理的方案,本文也是基于该套件的源码所引出来的权限管理解决方案。

    结语

    对程序员最大的挑战,并不是能否掌握了哪些编程语言,哪些软件框架,而是对业务和需求的理解,然后在此基础上,把要点抽象出来,写成计算机能理解的语言。
    最后,希望这篇文章,能够帮助你对权限管理这一课题增加多一点点理解。

    写作参考

    17 条回复    2018-02-13 10:59:54 +08:00
    jedrek
        1
    jedrek  
       2015-03-29 22:04:20 +08:00   2
    权限控制是程序的事,跟是否RESTful设计没有半点关系
    JerryC
        2
    JerryC  
    OP
       2015-03-29 22:12:05 +08:00
    @jedrek 我的意思是基于REST ful怎么设计权限控制,可能是我的标题出现歧义了
    tunetoystory
        3
    tunetoystory  
       2015-03-29 22:13:13 +08:00
    @JerryC auto token 头呀
    tunetoystory
        4
    tunetoystory  
       2015-03-29 22:13:28 +08:00
    @JerryC 打错 auth
    zieglar
        5
    zieglar  
       2015-03-29 22:25:17 +08:00
    做为一个 Sails.js 的使用者,从这个代码来看我觉得很蛋疼的
    强制定义的东西太多
    其实直接用 OAuth2.0 的 scope 就可以解决很多权限的问题
    ywisax
        6
    ywisax  
       2015-03-30 00:18:08 +08:00
    mark
    fengchang
        7
    fengchang  
       2015-03-30 09:19:25 +08:00
    我也觉得auth token是对你标题的回答。内容和RESTful没有关系
    caixiexin
        8
    caixiexin  
       2015-03-30 09:44:18 +08:00
    先mark后看。。
    我觉得权限控制其实跟RESTful无关吧,传统的管理系统就采用 RBAC,开放式的api就采用OAuth认证,都是程序上实现的逻辑,而RESTful只是对这些程序以及资源在url上一种优雅的描述。
    个人看法,大牛轻拍= =||
    hbin
        9
    hbin  
       2015-03-30 09:44:42 +08:00
    严格来讲,应该用 PATCH 而不是 PUT 去更新(FYI: http://tools.ietf.org/html/rfc5789)
    luchen3256
        10
    luchen3256  
       2015-03-30 09:59:27 +08:00
    这个图是用什么工具画的?
    JerryC
        11
    JerryC  
    OP
       2015-03-30 10:22:04 +08:00
    @luchen3256 ProcessOn
    JerryC
        12
    JerryC  
    OP
       2015-03-30 10:23:14 +08:00
    @zieglar 真的!?我去研究看看
    JerryC
        13
    JerryC  
    OP
       2015-03-30 10:24:40 +08:00
    但是看各位的评论,就能让我收获良多呀~~
    tabris17
        14
    tabris17  
       2015-03-30 13:48:20 +08:00
    使用HTTP协议的基本身份验证。添加Authorization头部
    reorx
        15
    reorx  
       2015-03-31 10:04:28 +08:00 via iPhone
    @caixiexin +1

    另外对一个资源的操作不一定只有 CRUD 四种,所有符合系统逻辑的原子操作都是,可以理解为你为某种资源的操作所封装的函数,permission 是用来控制是否允许用户对这些函数进行调用
    wuyu1998
        16
    wuyu1998  
       2015-04-05 14:53:00 +08:00
    1个角色,拥有n个权限。
    2个角色的权限交集,应该允许非空。

    权限 <===> 角色 <===> 用户
    感觉3者之间都是多对多的关系。而且,不允许将权限直接赋予用户。

    你描述的模型,只限制到表的记录级别,字段级别的权限控制,也应该有。
    如果要求控制到字段级别,RESTful的返回,很麻烦。
    laball
        17
    laball  
       2018-02-13 10:59:54 +08:00
    角色与权限的关系:一个角色拥有一堆权限,一个权限却只能属于一个角色,所以它们是一(角色)对多(权限)的关系

    好像有点不对吧!!!!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4317 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 04:04 PVG 12:04 LAX 20:04 JFK 23:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86