OAuth是线程安全的吗?

6

对我来说,OAuth的访问令牌/刷新令牌流程似乎非常不安全。帮助我更好地理解它。

假设我正在集成使用OAuth的API(例如此类)。我拥有我的访问令牌并进行API调用-世界上一切都很好。但是,然后我的访问令牌过期了,我需要一个新的令牌。没问题,我使用我获得的刷新令牌,然后我获得了一个新的访问令牌。

以上所有内容听起来都很好... 但在多线程世界中不是这样的。也就是说,如果以上所有操作在不同的线程上的确切相同的时间发生两次(例如,两个用户同时针对同一对象请求API调用),并且在任何给定时间只能有一个访问令牌存活,那么不会其中一个取消另一个吗?在高事务应用程序中,这种情况会经常发生。

我强烈感觉这是一个愚蠢的问题,但我无法理解如何使其线程安全。


多线程是一个问题。问题也在于,如果第一个“refresh_token”响应在网络上丢失了,那么下一个“refresh_token”调用可能会返回“invalid_grant”,如果服务器在每个调用上撤销了刷新令牌(规范允许这样做)。 是的,不幸的是,规范允许这种非线程安全、非错误容忍的行为。 - xmedeko
2个回答

6

Oauth是一个协议。它取决于特定的实现是否“线程安全”。

Oauth2 != Oauth: OAuth 2与OAuth 1有何不同?

而REST API(如您提到的)本质上是无状态的,因此没有“线程安全”的问题。

最后,在这里有一篇关于如何在多线程应用程序之间共享OAuth2凭证的好文章(即,一旦您建立了凭证):

优化OAuth 2.0请求

在多线程应用程序中,凭证应该在线程之间共享。刷新凭证应该同步执行以避免竞态条件。

客户端库使在线程之间共享凭证变得简单。每个客户端库都有一个会话(或用户)对象,它使用凭证构造并在其生命周期内重复使用。要在线程之间共享凭证,只需使用相同的凭证构建每个会话。在所有客户端库中,凭证都是线程安全的对象,并且在访问令牌过期时会同步刷新它自己。

例如,在Java客户端库中,您将创建一个凭证作为单例并在所有会话之间共享。


2
谢谢!那个链接非常有帮助,特别是这部分内容:“在多进程或分布式应用程序中,共享凭据需要您将其持久化。为了确保多个进程或服务器不会同时尝试刷新凭据,导致过多的刷新请求,我们建议在一个中央位置主动刷新凭据并在进程/服务器之间共享它。” - filmnut

2
我遇到了oauth grant_type password流程的一些问题。
当我的应用程序请求受保护的资源时,它会使用Spring WebClient中的ExchangeFilterFunction发出请求以获取访问令牌。如果access_token已过期,则应用程序会发出新的请求。
问题是:在我的实现中,如果一个线程检测到access_token已过期,它会发出请求以获取新令牌。与此同时,其他线程也会这样做,最终可能有N个线程同时尝试获取新的access_token。
解决此问题的最快且最原始的方法是阻塞代码段以防止其他线程从中获取新令牌(例如Java中的同步关键字)。这样只会发出一个请求,但是这将阻塞所有线程。当第一个线程接收到新的令牌时,其他线程将被释放,但现在它们不再需要发出请求,因为它们会检测到有效的令牌。
正如先前所述,这是实现特定的调整。我不知道Spring Security是否会关注这一点,但据我所知,oauth协议中没有规定如何处理此问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接