授权我的应用程序后,我通过头部传递oauth凭据来请求访问令牌。签名和标题是通过此代码生成的;
API_module = 'oauth'
API_RESTful = 'access_token'
if renewal:
API_RESTful = 'renew_access_token'
production_url = 'https://etws.etrade.com/{0:s}/{1:s}'.format(API_module, API_RESTful)
oauth_timestamp = int(time.time())
rand_str = lambda n: ''.join([random.choice(string.hexdigits) for i in range(n)])
oauth_nonce = rand_str(40)
key = oauth_consumer_secret + \
'&' + \
quote_plus(oauth_token_secret)
base_string = quote_plus('GET') + '&' + \
quote_plus('https://etws.etrade.com/oauth/access_token') + '&' + \
quote_plus('oauth_consumer_key={}&'.format(oauth_consumer_key)) + \
quote_plus('oauth_nonce={}&'.format(oauth_nonce)) + \
quote_plus('oauth_signature_method=HMAC-SHA1&') + \
quote_plus('oauth_timestamp={:d}&'.format(oauth_timestamp)) + \
quote_plus('oauth_token={}&'.format(quote_plus(oauth_token))) + \
quote_plus('oauth_verifier={}'.format(oauth_verification_code))
hashed = hmac.new(key.encode(), base_string.encode(), sha1)
oauth_signature = quote_plus(binascii.b2a_base64(hashed.digest())[:-1])
header_string = 'Authorization: OAuth ' + \
'realm="",' + \
'oauth_signature="{}",'.format(oauth_signature) + \
'oauth_nonce="{}",'.format(quote_plus(oauth_nonce)) + \
'oauth_signature_method="{}",'.format(oauth_signature_method) + \
'oauth_consumer_key="{}",'.format(oauth_consumer_key) + \
'oauth_timestamp="{}",'.format(str(oauth_timestamp)) + \
'oauth_verifier="{}",'.format(oauth_verification_code) + \
'oauth_token="{}"'.format(quote_plus(oauth_token))
headers_list.append(header_string)
response = curl_get_http(current_url=production_url)
生成这些标题;
Host: etws.etrade.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: keep-alive
Authorization: OAuth
realm="",
oauth_signature="fzqLbI8LBlBGs1Clp4eAgs09YuM%3D",
oauth_nonce="E447Ea1FCfbcCF0116fbdC47bE8E4aA4Cf7e3Aab",
oauth_signature_method="HMAC-SHA1",
oauth_consumer_key="4b6471c7ee",
oauth_timestamp="1501003943",
oauth_verifier="O5K2A",
oauth_token="BVuKV9Q7F93OxjbqY%2FzRmoqI0M%3D"
请求返回;
oauth_token=3W3hs5aSQPwMR%2FM0H0%2BPWhI%2Bo%3D&oauth_token_secret=SWvknmgEIgKzbN35bwwoNw%3D
通过用新的token_secret替换旧的token_secret来更新密钥。基本字符串也使用新标记值以及新的时间戳和随机数进行更新。这些新值用于生成新签名。
url_quotes = 'https://etws.etrade.com/market/rest/quote/{0:s}?detailFlag={1:s}'.format(symbols, flag)
oauth_timestamp = int(time.time())
rand_str = lambda n: ''.join([random.choice(string.hexdigits) for i in range(n)])
oauth_nonce = rand_str(40)
key = oauth_consumer_secret + \
'&' + \
oauth_token_secret
base_string = quote_plus('GET') + '&' + \
quote_plus('https://etws.etrade.com/market/rest/quote') + '&' + \
quote_plus('oauth_consumer_key={}&'.format(oauth_consumer_key)) + \
quote_plus('oauth_nonce={}&'.format(oauth_nonce)) + \
quote_plus('oauth_signature_method=HMAC-SHA1&') + \
quote_plus('oauth_timestamp={:d}&'.format(oauth_timestamp)) + \
quote_plus('oauth_token={}&'.format(oauth_token)) #+ \
#quote_plus('oauth_verifier={}'.format(oauth_verification_code))
hashed = hmac.new(key.encode(), base_string.encode(), sha1)
oauth_signature = quote_plus(binascii.b2a_base64(hashed.digest())[:-1])
header_string = 'Authorization: OAuth ' + \
'realm="",' + \
'oauth_signature="{}",'.format(oauth_signature) + \
'oauth_nonce="{}",'.format(quote_plus(oauth_nonce)) + \
'oauth_signature_method="{}",'.format(oauth_signature_method) + \
'oauth_consumer_key="{}",'.format(oauth_consumer_key) + \
'oauth_timestamp="{:d}",'.format(oauth_timestamp) + \
'oauth_verifier="{}",'.format(oauth_verification_code) + \
'oauth_token="{}"'.format(oauth_token)
headers_list.append(header_string)
response = curl_get_http(current_url=url_quotes)
将标题更改为;
Host: etws.etrade.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: keep-alive
Authorization: OAuth
realm="",
oauth_signature="v4xa%2FrCKtFRSUdHw%3D",
oauth_nonce="57FCC260F81b2fAd95AccA69FE07BFFcd06d83AB",
oauth_signature_method="HMAC-SHA1",
oauth_consumer_key="4b6471c7ee",
oauth_timestamp="1501003945",
oauth_verifier="O5K2A",
oauth_token="3W3hs5aSQPwMR%2FM0H0%2BPWhI%2Bo%3D"
并发出get_quote请求;
https://etws.etrade.com/market/rest/quote/TICK,ER,THAT,GOES,UP?detailFlag=FUNDAMENTAL
但是,不是引用,而是返回oauth问题。
<Error>
<message>oauth_problem=signature_invalid</message>
</Error>
我已经尝试在url中传递信息,但它返回相同的错误。请求中是否存在程序错误?是否应该使用新令牌而不更新签名?
(已发布的凭据已更改以保护无辜者)
答案 0 :(得分:2)
问题在于签名生成。
对于URL部分,您应该包括查询字符串之前的完整URL。在这个例子中,它将是:
base_string = quote_plus('GET') + '&' + \
quote_plus('https://etws.etrade.com/market/rest/quote/TICK,ER,THAT,GOES,UP') + '&' + \
连接oauth参数时,还应包括所有非Oauth查询参数。它们需要按照规范(https://oauth.net/core/1.0a/#anchor13)排序。在这种情况下,您需要包含detailFlag = FUNDAMENTAL作为您的第一个参数:
quote_plus('detailFlag=FUNDAMENTAL&') + \
quote_plus('oauth_consumer_key={}&'.format(oauth_consumer_key)) + \
此外,除了检索访问令牌之外,标题中不需要oauth_verifier。