请问 restful API 如果控制权限比较合适 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
heaton_nobu
V2EX    问与答

请问 restful API 如果控制权限比较合适

  •  
  •   heaton_nobu 2015-01-30 17:01:11 +08:00 6357 次点击
    这是一个创建于 3914 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如登录与不登录可调用的接口不同;
    登录的身份不同权限不同;
    身份相同的功能或是资源权限不同;

    请问如何才能简捷有效地控制这些情况的权限判断呢?

    15 条回复    2015-01-31 13:30:17 +08:00
    xiezefan
        1
    xiezefan  
       2015-01-30 18:48:45 +08:00   2
    一般有两种做法吧
    1. 使用access_token
    2. 使用HTTP Header 的 Authorization

    access_token一般用在get请求中, 因为很容易被捕获到, 所以一般设计为有时效性的, 例如 一次性的accss_token, 或者 1小时内有效.

    Authorization的话, 一般以这种形式提交上去
    Authorization : Basic base64_auth_code
    其中 base64_auth_code 用是 username + ":" + api_secret 做 base64编码, 因为base64是可逆的, 所以如果 api_secret 是使用用户的password等敏感信息的话, 可以考虑做 md5加密.
    如 Authoirzation : Basic Base64(username:md5(password))

    在服务端的话, 可以考虑在controller层写filter过滤用户权限, 并做响应的转发.
    typcn
        2
    typcn  
       2015-01-30 18:52:10 +08:00
    我这种数据库永久存 SESSIONID 的是不是很奇葩。。。
    heaton_nobu
        3
    heaton_nobu  
    OP
       2015-01-30 19:51:55 +08:00
    感谢楼上二位回答

    你们说的是如何登录的方法,可是登录之后调用接口的时候的权限判断如果能做到简单(从代码上)和快速(从服务端性能上)呢
    loading
        4
    loading  
       2015-01-30 20:09:30 +08:00   1
    请求来了,通过session里存的用户名(session存了id和用户名)得到权限(我数据库里存了用户组,同时也直接存了相应的权限字符串数组),这里多了一次sql查询,似乎不可避免。
    接着判断权限字符串里有没有相应的字符串。
    loading
        5
    loading  
       2015-01-30 20:11:31 +08:00
    当然,其实可以把前面的一次sql查询和后面的查询一起,只是比较复杂,没相应权限自然数据就空了,懒得写。
    n37r06u3
        6
    n37r06u3  
       2015-01-30 20:21:50 +08:00
    2种 ? 不都是直接在header里加token么
    xiezefan
        7
    xiezefan  
       2015-01-30 20:23:22 +08:00   2
    @heaton_nobu 我说的两种方案并不是登陆的方法. 实际上, HTTP协议是无状态协议 , 也就是说他不能记忆客户端请求的状态, access_token 和 session 都是通过验证用户登陆后返回的一个token&id来记录客户端的状态(是否登陆,是否有权限), 只不过区别在于session有很多现成的实现, 而access_token更多的是需要自己业务实现, 不过好处在于access_token不需要依赖cookies. 而Basic认证(就是使用Authorization)则是每次请求都携带认证信息. 对于每次API请求服务端都会做鉴权.
    无论上述哪种实现, 最好就是能做到对业务代码无侵入性(业务代码可以认为他每次接到的请求都是合法有权限的且不知道客户端是使用何种权限进入的).
    至于性能问题, 我曾经将用户权限存到内存数据库中, 如Redis, 请求的时候, 从内存中取数据并鉴权性能还可以接收, 至于如何存储用户权限以达到最少计算次数与最低复杂度, 要依靠你的项目而定. 如果用户量太大的话, 可以采用LRU(最近最久未使用)等算法. 讲太久未调用API的user从内存数据库中删除, 当再次调用的时候才从数据库中读到内存.
    xiezefan
        8
    xiezefan  
       2015-01-30 20:29:28 +08:00
    @n37r06u3 才疏学浅, 只是从经验触发吧. 嘻嘻. 以我接触的API为例子, 新浪微博的API大多采用access_token的形式, JPush则采用Basic认证
    heaton_nobu
        9
    heaton_nobu  
    OP
       2015-01-30 23:52:57 +08:00
    @xiezefan 非常感谢说了这么多
    就是说登录后将该用户对应的权限放入内存是吧,redis还没用过,改天试试
    可服务端放入session也是在内存中啊,请问这个性能和redis比如何?
    清除长时间未调用API的用户数据还要单独开一个进程去跑吗?
    Agromania
        10
    Agromania  
       2015-01-31 00:10:20 +08:00   2
    权限如何控制和restful API没有关系,一个安全的系统都是分为三步,
    1. 认证
    2. 授权
    3. 审计

    1楼说的是一个Restful API常用的认证、授权方式,验证你是否合法用户,识别区分你的用户身份,这先是第一步Authentication
    然后才是根据你描述的需求,按照身份和资源进行授权Autherization,如何在服务端判断一个指定身份对哪些资源拥有权限,要你自己去设计数据结构,关联查询,和相应的缓存机制,根据你的架构不同而不同。
    在OAuth方式中在授权以后会给你一个access_token,权限令牌,这个令牌对应的权限是保存在服务器上的。可以是数据库,可以是文件,可以是内存,但是对比的时候当然都是程序在内存里进行计算的。
    然后很多系统会忘记的一步也是很重要的一步就是审计,Accouting,记录下该身份对资源进行的访问和操作。
    Agromania
        11
    Agromania  
       2015-01-31 00:33:44 +08:00
    1. 登录和不登录的访问区分,简单的方法,你可以在应用入口判断,需要登录的接口如果没有认证就不可访问;
    当然你也可以把没有“登录”的用户认证为“匿名身份”,和其他身份一起作为一种身份在第二条中统一处理,如果可以,建议用这一种方式,这样对“匿名身份”同样可以认证、授权,并且审计,记录其调用信息。
    2.身份不同,可用的功能不同
    因为功能是确定而且有限的,你可以定义每个功能为整数,

    查看1,创建2,修改3,删除4,提交5,关闭6等等
    或者按照模块分:
    帖子模块:查看1,创建2....
    工单模块:查看1,创建2....

    权限可以按位存储,比如一个用户A有帖子的查看和修改权限,工单的查看、关闭和删除权限
    A -- 帖子模块 -- 5 (2进制是000101)
    A -- 工单模块 -- 41 (101001)
    判断A是否有某模块的某权限只要做位运算即可以,这种方法管理的权限非常灵活,全部原子化,性能也快。

    身份相同可访问的资源ID不同,这个看你们身份与资源的对应数量关系,可能不同情况应当要采用不同的结构
    heaton_nobu
        12
    heaton_nobu  
    OP
       2015-01-31 00:38:01 +08:00
    @Agromania 多谢
    请问最后的审计步骤是相当于一个志吗?有其他的用途吗?
    Agromania
        13
    Agromania  
       2015-01-31 00:41:54 +08:00
    @heaton_nobu 是相当于一个日志,就是日志的所有用途~好像应该没有其他用途了。
    这个日志可以记录资源调用的情况,趋势,流量等等……如果是资源计费或次数限制的系统,这个日志也是计费的依据~
    yangzh
        14
    yangzh  
       2015-01-31 13:12:42 +08:00 via iPhone
    我最近也在研究这个问题。我说说我查到的建议:用 http auth 的方法,首先附上 userid and password来 post /login 然后服务器端返回有时限的 token,之后客户端每次访问资源的时候都加上 userid and tocken 或者 userid and password。全程用 https。

    以上是 cs 架构。

    如果允许第三方授权什么的就需要 oauth 了。参照 github api 设计即可。
    JamesRuan
        15
    JamesRuan  
       2015-01-31 13:30:17 +08:00 via Android
    最近在设计一个论坛,刚好遇到了这个问题。
    认证,授权,审计思路是很好的,目前这一套并没有什么易用的一站式解决方案,需要根据具体业务具体分析。
    比如我的设计中,操作权限表中的用户组就分为静态用户组与动态用户组,以实现更加细粒度的控制。系统会储存用户最后一次对某资源的操作,做各类分析用,其中有设置的操作将计入日志。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2637 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 14:42 PVG 22:42 LAX 07:42 JFK 10:42
    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