ChatGPT解决这个技术问题 Extra ChatGPT

如何识别 OAuth 令牌是否已过期?

我的 iOS 移动应用程序使用使用 OAuth2.0 协议实现的服务。 OAuth 访问令牌附带一个刷新令牌和一个 expires_in 字段。我在我的应用程序中保存了刷新令牌和访问令牌到期时间,但不知道何时使用它们。

那么使用这个 expires_in 的通常和最佳实践是什么?

如何识别我的访问令牌已过期?

是否有一种常见的 Web 服务错误格式表明我的访问令牌已过期?


C
Community

以下是有关 OAuth 2.0 令牌刷新的信息。

定义过期

OAuth 2.0 标准 RFC 6749expires_in 字段定义为到期秒数:

expires_in:推荐。访问令牌的生命周期(以秒为单位)。例如,值“3600”表示访问令牌将在响应生成后一小时内过期。如果省略,授权服务器应该通过其他方式提供过期时间或记录默认值。

令牌刷新处理:方法 1

在收到有效的 access_tokenexpires_in 值、refresh_token 等后,客户端可以通过存储过期时间并在每个请求上检查它来处理它。这可以使用以下步骤来完成:

将 expires_in 转换为过期时间(epoch、RFC-3339/ISO-8601 日期时间等)存储每个资源请求的过期时间,检查当前时间与过期时间,并在资源请求之前发出令牌刷新请求,如果access_token 已过期

一个示例实现是 Go oauth2 库,它将 expires_in 值转换为令牌 expiry property 中的 RFC 3339 日期时间。 expiry 不是由 OAuth 2.0 标准定义的,但在这里很有用。

检查时间时,请确保您是同一时间,例如,通过将所有时间转换为纪元或 UTC 时区来使用相同的时区。

除了收到新的 access_token 外,您将来可能还会收到一个新的 refresh_token,其到期时间会更长。如果您收到此信息,您应该存储新的 refresh_token 以延长会话的生命周期。

令牌刷新处理:方法 2

另一种处理令牌刷新的方法是在收到无效令牌授权错误后手动刷新。这可以通过以前的方法或单独完成。

如果您尝试使用过期的 access_token 并收到无效令牌错误,则应执行令牌刷新(如果您的刷新令牌仍然有效)。由于不同的服务可以对过期令牌使用不同的错误代码,因此您可以跟踪每个服务的代码,或者跨服务刷新令牌的简单方法是在遇到 4xx 错误时简单地尝试一次刷新。

无效的访问令牌错误

以下是一些流行服务的错误代码:

Facebook:错误 467 访问令牌无效 - 访问令牌已过期、被撤销或无效 - 处理过期的访问令牌。 LinkedIn:错误 401 未经授权。贝宝:错误 401 未经授权。

实现

Zapier服务是一种实现授权错误重试后刷新的服务。

https://i.stack.imgur.com/P8K0z.png

刷新令牌过期

如果您的 refresh_token 也已过期,您将需要再次完成授权过程。

OAuth 2.0 spec 未定义刷新令牌过期或如何处理它,但是,当刷新令牌过期时,许多 API 将返回 refresh_token_expires_in 属性。不同的 API 会以不同的方式处理刷新令牌过期,因此查看每个 API 的文档很重要,但通常您在刷新访问令牌时可能会收到一个新的刷新令牌。过期应该以类似的方式处理,例如将 refresh_token_expires_in 转换为 RFC 3339 日期时间 refresh_token_expiry 值。

一些示例包括 LinkedIneBayRingCentral。在 LinkedIn API 中,当您刷新访问令牌时,您将收到一个带有递减 refresh_token_expires_in 属性的刷新令牌,该属性以原始刷新令牌到期时间为目标,直到您需要再次进行身份验证。 RingCentral API 将返回具有静态时间的刷新令牌,因此如果令牌刷新和刷新令牌更新一致完成,用户不必再次进行身份验证。


您好,非常感谢您的回复!在查看过期时间时,如果用户更改了设备时间怎么办?会不会导致频繁刷新访问令牌?关于检查无效令牌错误,您对 oAuth 服务器将返回的响应代码和错误格式有什么想法吗?对于所有 oAuth 服务器,这将是相同的错误响应吗?
经常发生的设备时间变化有哪些用例?时区更改应自动处理。由于标准中没有定义无效令牌错误代码,因此不同的服务选择了上面列出的不同错误代码。如前所述,一个简单的刷新方法可能是在出现 4xx 错误时尝试单次刷新。
Spotify 返回未经授权的 401
聚会迟到了,但您怎么知道 refresh_token 是否无效? :O
IETF RFC 6749 未定义刷新令牌过期或如何处理它,但许多 API 实现了 refresh_token_expires_in 属性,我已使用此信息更新了答案。
G
Gary Archer

推荐上面的方法 2,因为 401 可能由于多种原因而发生,例如更新令牌签名证书或时钟差异:

每次 API 请求后检查 401

获取新令牌 - 仅一次

重试 API 请求 - 仅一次

我已经实现了很多成功的 OAuth 客户端并且一直使用这种技术——并且避免在我的客户端代码中读取 expires_in 字段


我打算在我的应用程序中实现代码检查 expires_in 字段,但遇到了很多时区和用户更改设备时间的问题。因此,我将按照您上面所说的方式实现我的 NetworkingClient。
令牌颁发者返回的过期时间不应该与用户时区无关吗?我希望它是UTC。
R
Robert

该问题指定了 iOS,但作为任何工具集的一般原则,对于基于服务器的解决方案,将令牌存储在服务器内存缓存中,并将缓存到期日期时间设置为与令牌的到期时间相同。

在需要身份验证令牌的任何其他端点之前调用以下函数。

这样,它会从缓存中获取令牌,或者如果缓存已过期(与令牌本身过期的时间相同)则获取新令牌。

对于 .NET:

    private async Task<string> GetAuthToken()
    {
        string cacheKey = "AuthToken";

        if (!_memoryCache.TryGetValue(cacheKey, out string authToken))
        {
            // Token not in cache, so get fresh one:

            // Do call for token
            HttpClient client = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, *url*);

            // Add Headers
            ...
            // Make call
            var response = await client.SendAsync(request);
            string responseContent = await response.Content.ReadAsStringAsync();

            // Check the call success/failure
            if (!response.IsSuccessStatusCode)
            {
                return null;
            }

            JObject authObj = JObject.Parse(responseContent);
            authToken = (string)authObj["access_token"];
            string authTokenExpires = (string)authObj["expires_in"];

            // Save data in cache.
            MemoryCacheEntryOptions staticDataCacheMemoryOptions = new MemoryCacheEntryOptions()
                    // Keep in cache until expired by Provider
                    .SetAbsoluteExpiration(DateTime.Now.AddSeconds(Convert.ToInt32(authTokenExpires)));

            _memoryCache.Set(cacheKey, authToken, staticDataCacheMemoryOptions);
        }

        return authToken;
    }

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅