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



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

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

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

所以,我的问题有三个方面:

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

我看到你的设计有几个问题。

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

嗯。这不是一个好的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 Basic 身份验证交换。我写了 Flask-HTTPAuth 扩展,你可以看看我是如何实现这个交换的,并将代码复制到你的视图函数中,这样你就可以只在必要时发出它。我希望这能澄清一些事情。

相关内容

最新更新