flask 应该怎么保护后端 api 接口,为接口增加权限机制? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mzmxcvbn
V2EX    Flask

flask 应该怎么保护后端 api 接口,为接口增加权限机制?

  •  
  •   mzmxcvbn 2017-06-06 09:02:24 +08:00 8717 次点击
    这是一个创建于 3099 天前的主题,其中的信息可能已经有所发展或是发生改变。
    新学上手,跌跌撞撞做了一个生产信息的展示系统,后端用 flask 提供 json 数据的 api 接口,前端用 ajax 去获取数据,定时更新。不同的生产数据应该要对应权限的人才能看到,现在我已经用 flask-login 做好了基本的用户登录及权限功能,但这只能保护特定页面不被访问到,可是 api 接口都是暴露在外面的,直接就能绕过页面,拿到 json 数据。我想知道怎么才能和 flask-login 一样,将接口保护起来。
    第 1 条附言    2017-06-06 10:24:22 +08:00
    比如现在有 2 个部门,要求是生产部只能看到生产数据,采购部只能看到采购数据。但现在用 flask-login,只能限制到生产部的人只可访以问生产数据的展示页面,采购部的人只可以访问采购数据的展示页面。可是由于数据都是通过后台 api 传过来的 json 数据,那么只要生产部的人知道了采购 api 的 url,他就能绕过页面限制,直接得到采购的 json 数据。我的意思就是怎样避免这种情况发生,把 api 保护起来,只对特定用户开放。
    21 条回复    2017-06-21 22:36:03 +08:00
    sivacohan
        1
    sivacohan  
    PRO
       2017-06-06 09:10:33 +08:00 via Android
    没太明白你的意思。
    是想要 login_required 吗?
    Kilerd
        2
    Kilerd  
       2017-06-06 09:11:21 +08:00
    API 的话不能用 flask-login,因为 API 访问是绕过 session 的(所谓的无状态访问)
    所以在访问 API 的时候,应该需要访问时加入一个“人为的 session ”,也就是 token。
    ddragonever
        3
    ddragonever  
       2017-06-06 09:30:53 +08:00
    自己写装饰器 装饰器里面定义自己需要的功能,对请求进行拦截处理就可以了,flask 的路由其实也是装饰器实现的

    @api.route('/api/res')
    @admin_required
    def test():
    # do something

    比如这里,自己定义一下 admin_required 就可以了
    ericls
        4
    ericls  
       2017-06-06 09:31:58 +08:00 via iPhone
    就 jwt 了吧 简单好用
    mzmxcvbn
        5
    mzmxcvbn  
    OP
       2017-06-06 10:23:59 +08:00
    @sivacohan 比如现在有 2 个部门,要求是生产部只能看到生产数据,采购部只能看到采购数据。但现在用 flask-login,只能限制到生产部的人只可访以问生产数据的展示页面,采购部的人只可以访问采购数据的展示页面。可是由于数据都是通过后台 api 传过来的 json 数据,那么只要生产部的人知道了采购 api 的 url,他就能绕过页面限制,直接得到采购的 json 数据。我的意思就是怎样避免这种情况发生,把 api 保护起来,只对特定用户开放。
    mzmxcvbn
        6
    mzmxcvbn  
    OP
       2017-06-06 10:27:06 +08:00
    @ericls 我看了一下这个 JWT,我想问一下这个东西可以和 flask-login 并存吗。两套东西怎么互通呢?
    bolide2005
        7
    bolide2005  
       2017-06-06 10:56:58 +08:00
    @mzmxcvbn 知乎上的问题也是你问的吗?我感觉我答案里说清楚了啊。jwt 只是身份验证的标志,通过 flask-login 登录后,生成一个 token 返回给前端,以后就可以通过这个 token 找到对应的用户,用户有没有权限访问 api 就可以通过后端来验证了。

    其实关键的地方不在于 jwt 或者别的什么 token,而在于两点:
    1.用户要有权限等级的分配,你需要在用户系统里加入权限的概念,不同的用户访问不同等级的 API 接口,这一步其实不需要 jwt,flask-login 也是能实现的
    2.对每一次用户的请求,要识别出是哪个用户发起的,基本实现的方式就是写 cookie。

    建议使用 jwt 只是因为它很方便,不需要在后端数据库里维护一个 token-user 的表,把权限直接写进 token 里,每次解析出来校验一下就行了。
    qq316107934
        8
    qq316107934  
       2017-06-06 11:03:36 +08:00 via Android
    我觉得楼主需要的是用户角色管理
    awanabe
        9
    awanabe  
       2017-06-06 11:56:23 +08:00
    在 API 上加个权限控制,需要用户登陆之后保存到客户端的的 token 或者 cookie
    siteshen
        10
    siteshen  
       2017-06-06 13:22:32 +08:00
    写成 decorator 更好, 实现函数 is_in_prod_department(user) 可视复杂成都,有下面三个方案供参考:

    1. 增加字段 user.department (一对一)
    2. 增加表 user_department (多对多)
    3. 参考 django 的 user 系统,user, user_group, user_permission, group_permission , permission

    def prod_department_only_api():
    if not flask_login.current_user.is_authorized:
    abort(400)

    if not is_in_prod_department(flask_login.current_user):
    abort(403)

    # logic here
    alvy
        11
    alvy  
       2017-06-06 13:38:34 +08:00
    jwt+1
    brucedone
        12
    brucedone  
       2017-06-06 14:13:02 +08:00
    apigateway 啊,保护 api,从我做起,写一个网关系统,有认证机制
    Responsible
        13
    Responsible  
       2017-06-06 14:19:43 +08:00 via Android
    ipconfiger
        14
    ipconfiger  
       2017-06-06 14:39:18 +08:00
    楼主需要的是一个通用的 RBAC 系统
    elvis_w
        15
    elvis_w  
       2017-06-06 15:32:10 +08:00
    onyourroad
        16
    onyourroad  
       2017-06-06 20:13:56 +08:00
    不知道 flask 有没有 Django REST framework 这种框架,这个可以满足你的需求。
    yanzixuan
        17
    yanzixuan  
       2017-06-06 22:19:29 +08:00
    我是在 header 里面加 token 解决的。。。就是不知道是不是标准做法。。
    mengzx
        18
    mengzx  
       2017-06-07 07:54:55 +08:00 via Android
    @yanzixuan 以前用的一个数据公司的 api 就是 header 里面加 token 的
    KgM4gLtF0shViDH3
        19
    KgM4gLtF0shViDH3  
       2017-06-07 19:23:41 +08:00 via Android
    post 的数据里面加个 token 字段,用 token 来分辨登陆的人
    mingyun
        20
    mingyun  
       2017-06-10 09:34:44 +08:00
    赞同 7 楼 jwt 使用很简单,支持各个语言
    workwonder
        21
    workwonder  
       2017-06-21 22:36:03 +08:00 via Android
    为应对简单的场景并保持一定灵活性,我这样搞:

    ```
    @app.route('/api/a')
    @user_passes_test(lambda u: u.group == 'Role-A')
    def view_a() :
    pass
    ```

    首先要自己实现 user_passes_test 装饰器,lambda 就是一段检测用户是否有权访问的代码。我举的这个例子还体现了根据用户所属的分组来划分权限的思路。

    还可以基于此搞一些常用封装,比如:

    login_required = user_passes_test(lambda u: u.is_authenticated == True)
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     831 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 22:07 PVG 06:07 LAX 14:07 JFK 17:07
    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