当某些方法需要身份验证而某些方法不需要时,在Flask中构建RESTful API

时间:2015-01-03 08:37:43

标签: python rest authentication flask flask-security

我在Flask中创建一个新的RESTful API,它应该接受给定对象的GET(用于请求资源)和PATCH(用于执行各种增量,非幂等更新)。问题是,某些已修补的数据必须经过身份验证,有些数据不应该是。

为了澄清一个例子,让我们说我正在构建一个应用程序,让每个人都可以查询资源被点击的次数以及查看该页面的次数。它还让人们在javascript中对资源进行更新,说资源再次被点击(未经身份验证,因为它来自前端)。它还允许经过身份验证的后端增加页面被查看的次数。

所以,遵循RESTful原则,我认为所有三个动作都应该在同一条路径上完成 - 类似于/pages/some_page_name,它应该同时接受GET和PATCH,并且应该接受两种不同类型的数据。补丁。问题是在Flask中,看起来身份验证始终是围绕一个方法使用装饰器进行的,所以如果我有一个类似@app.route('/pages/<page_id>', methods=['GET', 'PATCH'])的方法,我的身份验证将通过像@auth.login_required这样的装饰器完成。整个方法,这将迫使不需要身份验证的方法进行身份验证。

所以,我的问题有三个:

  1. 我是否正确构建在同一路径下提到的所有三个动作/这是否重要?
  2. 如果我是对的,这很重要,我如何只要求对一种PATCH进行身份验证?
  3. 如果这不重要,那么构建此API的更好或更简单的方法是什么?

1 个答案:

答案 0 :(得分:1)

我发现你的设计存在一些问题。

  

假设我正在构建一个应用程序,让每个人都可以查询资源被点击的次数以及查看其页面的次数

嗯。这不是一个好的REST设计。您不能让客户端查询选择资源的“属性”,只选择资源本身。如果您的资源是“页面”,那么对/pages/some_page_name的GET请求应该返回类似这样的内容(在JSON中):

{
    'url': 'http://example.com/api/pages/some_page_name',
    'clicks': 35,
    'page_views': 102,
    <any other properties of a page resource here>
}
  

它还允许人们在javascript中对资源进行更新,说明资源再次被点击

“点击内容”是一个动作,因此它不是一个好的REST模型。我对你的项目了解不够,所以我错了,但我认为最好的解决办法就是让用户点击这个东西,然后服务器会收到某种请求(也许是GET来获取资源)被点击了?)。然后,服务器可以自行增加资源的clicks属性。

  

(未经验证,因为它来自前端)。

这可能很危险。如果您允许任何人更改您的资源,那么您可能会受到攻击,这可能是一个问题。没有什么能阻止我查看您的Javascript并对您的API进行逆向工程,然后发送虚假请求以人为地更改计数器。这可能是可接受的风险,但请确保您了解这可能发生。

  

另外,让经过身份验证的后端会增加页面被查看的次数。

后端?这是客户端还是服务器?听起来应该是客户。再一次,“递增”不是REST类型API的良好匹配。让服务器根据从客户端收到的请求来管理计数器。

假设我明白你在说什么,在我看来你只需要支持GET。服务器可以在收到请求时自行更新这些计数器,客户端无需为此烦恼。

更新:在下面的评论中提供了一些其他信息之后,我认为您可以做的是RESTful也是实施PUT请求(或PATCH如果你是部分资源更新。

如果您执行PUT,则客户端将发送上述相同的JSON表示,但它将递增相应的计数器。您可以在服务器中添加验证以确保计数器按顺序递增,如果发现它们不是,则返回400状态代码(对于某些经过身份验证的用户,可能会跳过此验证,由您决定)。例如,从上面的示例开始,如果您需要增加点击次数(而不是页面浏览量),请发送PUT请求:

{
    'url': 'http://example.com/api/pages/some_page_name',
    'clicks': 36,
    'page_views': 102
}

如果您使用PATCH,则可以删除不会更改的项目:

{
    'clicks': 36
}

老实说,我觉得这不是你问题的最佳设计。您在此处拥有非常特定的客户端和服务器,旨在相互协作。 REST对于分离的客户端和服务器来说是一个很好的设计,但如果你在线路的两边,那么REST并没有真正给你很多。

现在关于您的身份验证问题,如果您的PUT / PATCH需要有选择地进行身份验证,那么您只能在必要时发出HTTP基本身份验证交换。我编写了Flask-HTTPAuth扩展名,您可以查看我如何实现此交换并将代码复制到您的视图函数中,以便您只在必要时才能发布它。 我希望这能澄清一些事情。