在请求 oauthlib 的 oauth2session 中包含授权

如何解决在请求 oauthlib 的 oauth2session 中包含授权

从阅读各种文档来看,似乎 oauth2 提供者需要为刷新令牌请求选择授权。我正在使用似乎需要授权的 FitBit API。

我正在按照此处的说明使用 requests-oauthlib 刷新令牌: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#refreshing-tokens

一些设置代码(不是我使用的,但你明白了:

>>> token = {
...     'access_token': 'eswfld123kjhn1v5423',...     'refresh_token': 'asdfkljh23490sdf',...     'token_type': 'Bearer',...     'expires_in': '-30',# initially 3600,need to be updated by you
...  }
>>> client_id = r'foo'
>>> refresh_url = 'https://provider.com/token'
>>> protected_url = 'https://provider.com/secret'

>>> # most providers will ask you for extra credentials to be passed along
>>> # when refreshing tokens,usually for authentication purposes.
>>> extra = {
...     'client_id': client_id,...     'client_secret': r'potato',... }

>>> # After updating the token you will most likely want to save it.
>>> def token_saver(token):
...     # save token in database / session
from requests_oauthlib import OAuth2Session
client = OAuth2Session(client_id,token=token,auto_refresh_url=refresh_url,auto_refresh_kwargs=extra,token_updater=token_saver)
r = client.get(protected_url)

但是,我接到了这个电话:

MissingTokenError: (missing_token) Missing access token parameter.

我知道我的令牌已过期,但为什么刷新不起作用?

解决方法

图书馆在这方面被打破了。见#379

你可以像这样解决它:

def _wrap_refresh(func):
    def wrapper(*args,**kwargs):
        kwargs['auth'] = (client_id,client_secret)
        kwargs.pop('allow_redirects',None)
        return func(*args,**kwargs)
    return wrapper

client = OAuth2Session(client_id,token=token,auto_refresh_url=refresh_url,token_updater=token_saver)
client.refresh_token = _wrap_refresh(client.refresh_token)
,

编辑:下面仍然有一些有用的信息,但覆盖 auth 函数意味着我的实际 API 请求现在失败(即下面不是正确答案)我不确定我是怎么得到的我上次尝试工作的一个请求。它可能只是返回了一个错误(在 json 中)而不是抛出错误,我只是假设没有引发错误意味着它确实在工作。 请参阅 OrangeDog 的正确解决方法(直到库修复)。

好吧,就在抛出 MissingTokenError 之前,我检查了 FitBit 服务器响应。结果我收到一条错误消息,说身份验证不正确。

这本身可能是一个有用的点,可以花一会。 MissingTokenError 当响应不包含预期的令牌时似乎发生。如果您可以调试并更仔细地查看响应,您可能会发现服务器提供了更多关于为什么您的请求格式错误的详细信息。我去了错误的位置并添加了打印语句。这让我可以看到来自 FitBit 的 JSON 消息。无论如何,这种方法可能对其他人获得 MissingTokenError 有用。

    if not 'access_token' in params:
        print(params)
        raise MissingTokenError(description="Missing access token parameter.")

无论如何,经过一些进一步的调试,没有设置身份验证。此外,我的客户 ID 和机密被张贴在正文中(这可能不是问题)。在 FitBit 示例中,客户端 ID 和密码没有发布在正文中,而是通过身份验证传递的。所以我需要客户端将身份验证传递给 FitBit。

那么问题来了,我如何进行身份验证。目前缺乏这方面的文档。但是,查看会话对象时,我发现了一个正在设置的 .auth 属性以及对问题的引用(#278)。在该问题中,为手动身份验证设置提供了一种解决方法(如下所示):https://github.com/requests/requests-oauthlib/issues/278

注意,oauth 会话继承自请求会话,所以对于非常了解请求的人来说,这可能很明显......

不管怎样,解决办法就是在初始化会话后设置auth参数。由于 FitBit 不需要正文中的客户端 ID 和密码,因此我也删除了传递额外内容(同样,这可能是一个小问题,并没有真正影响事情):

import os
import json
from requests.auth import HTTPBasicAuth
from requests_oauthlib import OAuth2Session

client_id = ""
client_secret = ""

with open("tokens.json","r") as read_file:
    token = json.load(read_file)       

save_file_path = os.path.abspath('tokens.json')

refresh_url = 'https://api.fitbit.com/oauth2/token'

def token_saver(token):    
    with open(save_file_path,"w") as out_file:
        json.dump(token,out_file,indent = 6) 

#Note,I've removed the 'extras' input
client = OAuth2Session(client_id,token_updater=token_saver)
#This was the magic line ...
auth = HTTPBasicAuth(client_id,client_secret)
client.auth = auth

url = 'https://api.fitbit.com/1.2/user/-/sleep/date/2021-01-01-2021-01-23.json'
wtf = client.get(url)

好的,我想我正确地复制了该代码,目前我的代码有点混乱。关键部分很简单:

client.auth = auth

在客户端启动之后。

注意,我的令牌包含一个 expires_at 字段。我不认为会话在确切时间方面处理 expires_in。换句话说,我认为 expires_in 仅在其值小于 0 时才会导致刷新。我认为它不会查看对象的创建时间并启动计时器或设置属性以了解 {{ 1}} 是相对的。另一方面,expires_in 字段似乎提供(我认为)一个经过检查以确保令牌在请求时未过期的字段,因为 expires_at 是真实世界,非相对,时间。这是我的令牌字典(带有假令牌和 user_id):

expires_at

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?