V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mzmxcvbn
V2EX  ›  Flask

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

  •  
  •   mzmxcvbn · 2017-06-06 09:02:24 +08:00 · 7825 次点击
    这是一个创建于 2488 天前的主题,其中的信息可能已经有所发展或是发生改变。
    新学上手,跌跌撞撞做了一个生产信息的展示系统,后端用 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  
       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 的
    bestkayle
        19
    bestkayle  
       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   ·   我们的愿景   ·   实用小工具   ·   2749 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:36 · PVG 20:36 · LAX 05:36 · JFK 08:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.