我正在尝试在python中编写一个小脚本来连接到BOX,但它一直给我这个错误:'NoneType'对象没有属性'encode'
起初我以为这是在我编写Passphrase时引起的,但似乎并非如此。当我尝试使用access_token = auth.authenticate_instance()进行身份验证时,脚本失败。如果我没有它运行脚本它似乎工作。可能导致这种情况的原因是什么?
提前感谢您提供的任何帮助。
这就是我所拥有的:
import keyring
from boxsdk import JWTAuth
from boxsdk import Client
def read_tokens():
"""Reads authorisation tokens from keyring"""
# Use keyring to read the tokens
auth_token = keyring.get_password('Box_Auth', 'mybox@box.com')
refresh_token = keyring.get_password('Box_Refresh', 'mybox@box.com')
return auth_token, refresh_token
def store_tokens(access_token, refresh_token):
"""Callback function when Box SDK refreshes tokens"""
# Use keyring to store the tokens
keyring.set_password('Box_Auth', 'mybox@box.com', access_token)
keyring.set_password('Box_Refresh', 'mybox@box.com', refresh_token)
Passphrase = 'xxxxxxx';
my_str_as_bytes = Passphrase.encode('UTF-8','strict')
auth = JWTAuth(
client_id='xxxxxxxxxx',
client_secret='xxxxxxxx',
enterprise_id='xxxxxxx',
jwt_key_id='xxxxxxx',
rsa_private_key_file_sys_path='/home/Marketscale/keys/private_key2.pem',
rsa_private_key_passphrase=my_str_as_bytes,
store_tokens=store_tokens,
)
access_token = auth.authenticate_instance()
这是错误的全文:
Traceback (most recent call last):
File "/home/Marketscale/Tests/JWTTest.py", line 37, in <module>
access_token = auth.authenticate_instance()
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/jwt_auth.py", line 186, in authenticate_instance
return self._auth_with_jwt(self._enterprise_id, 'enterprise')
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/jwt_auth.py", line 158, in _auth_with_jwt
return self.send_token_request(data, access_token=None, expect_refresh_token=False)[0]
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 298, in send_token_request
self._store_tokens(access_token, refresh_token)
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 233, in _store_tokens
self._store_tokens_callback(access_token, refresh_token)
File "/home/Marketscale/Tests/JWTTest.py", line 22, in store_tokens
keyring.set_password('Box_Refresh', 'mybox@box.com', refresh_token)
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyring/core.py", line 48, in set_password
_keyring_backend.set_password(service_name, username, password)
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyrings/alt/file_base.py", line 128, in set_password
password_encrypted = self.encrypt(password.encode('utf-8'), assoc)
AttributeError: 'NoneType' object has no attribute 'encode'
答案 0 :(得分:1)
我根本不知道您正在使用的API,但基于查看代码的一些想法:
从下往上完成堆栈跟踪,你有:
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyrings/alt/file_base.py", line 128, in set_password
password_encrypted = self.encrypt(password.encode('utf-8'), assoc)
AttributeError: 'NoneType' object has no attribute 'encode'
该代码位于https://github.com/jaraco/keyrings.alt/blob/master/keyrings/alt/file_base.py,密码(我们知道为None)是传递给set_password函数的最后一个参数。这是从:
调用的 File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyring/core.py", line 48, in set_password
_keyring_backend.set_password(service_name, username, password)
该代码位于https://github.com/jaraco/keyring/blob/master/keyring/core.py,密码又是set_password函数的最后一个参数。接下来,我们有:
File "/home/Marketscale/Tests/JWTTest.py", line 22, in store_tokens
keyring.set_password('Box_Refresh', 'mybox@box.com', refresh_token)
....这是你的代码,所以refresh_token必须是None。这意味着必须使用refresh_token为None调用store_tokens。下一个:
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 233, in _store_tokens
self._store_tokens_callback(access_token, refresh_token)
这是https://github.com/box/box-python-sdk/blob/master/boxsdk/auth/oauth2.py,再次表示调用了_store_tokens,并将refresh_token设置为None。起...
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 298, in send_token_request
self._store_tokens(access_token, refresh_token)
与最后一页在同一页面上的代码,但现在它更有趣了:
url = '{base_auth_url}/token'.format(base_auth_url=API.OAUTH2_API_URL)
headers = {'content-type': 'application/x-www-form-urlencoded'}
network_response = self._network_layer.request(
'POST',
url,
data=data,
headers=headers,
access_token=access_token,
)
if not network_response.ok:
raise BoxOAuthException(network_response.status_code, network_response.content, url, 'POST')
try:
response = network_response.json()
access_token = response['access_token']
refresh_token = response.get('refresh_token', None)
if refresh_token is None and expect_refresh_token:
raise BoxOAuthException(network_response.status_code, network_response.content, url, 'POST')
except (ValueError, KeyError):
raise BoxOAuthException(network_response.status_code, network_response.content, url, 'POST')
self._store_tokens(access_token, refresh_token)
return self._access_token, self._refresh_token
因此我们知道调用了self._store_tokens,并将refresh_token设置为None,这意味着expect_refresh_token必须为False,否则会引发BoxOAuthException。而且,实际上,如果我们查看堆栈跟踪中的下一行,我们可以看到:
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/jwt_auth.py", line 158, in _auth_with_jwt
return self.send_token_request(data, access_token=None, expect_refresh_token=False)[0]
这告诉我,当你使用JWT Auth时,你不应该期待一个刷新令牌。鉴于密钥环的文件后端在传递一个None作为密码时会爆炸,听起来你需要以不同方式处理None情况。所以,我建议更改你提供的store_tokens函数,以便它忽略刷新令牌,如果它是None,即:
def store_tokens(access_token, refresh_token):
"""Callback function when Box SDK refreshes tokens"""
# Use keyring to store the tokens
keyring.set_password('Box_Auth', 'mybox@box.com', access_token)
if refresh_token is not None:
keyring.set_password('Box_Refresh', 'mybox@box.com', refresh_token)
...或者它将None转换为密钥环文件后端可以正常处理的东西 - 也许一个空字符串可以解决这个问题:
def store_tokens(access_token, refresh_token):
"""Callback function when Box SDK refreshes tokens"""
# Use keyring to store the tokens
keyring.set_password('Box_Auth', 'mybox@box.com', access_token)
if refresh_token is None:
refresh_token = ""
keyring.set_password('Box_Refresh', 'mybox@box.com', refresh_token)
一个警告 - 就像我说的,我不知道这些API - 既不是盒子,也不是你正在使用的钥匙圈。但基于那里的代码,做这样的事情听起来值得一试。