Python的Oauth1.0 API问题

时间:2014-11-22 09:35:14

标签: python oauth

我试图让magiccardmarket.eu API身份验证在Python中运行,但无论我是否使用rauth或requests_oauthlib,我都会得到403.

我的代码是:

#!/usr/bin/python

import logging

import rauth
import requests_oauthlib

logging.basicConfig(level=logging.DEBUG)

mkm_app_token = 'B7VI9Qg2xh855WtR'
mkm_app_secret = '<cut>'
mkm_access_token = 'LQj2rUwOFUJsmuJvCTlny1UzGZSXzHjo'
mkm_token_secret = '<cut>'

url = 'https://sandbox.mkmapi.eu/ws/v1.1/account'

# session = rauth.OAuth1Session(
#   consumer_key=mkm_app_token,
#   consumer_secret=mkm_app_secret,
#   access_token=mkm_access_token,
#   access_token_secret=mkm_token_secret,
# )

session = requests_oauthlib.OAuth1Session(
    mkm_app_token,
    client_secret=mkm_app_secret,
    resource_owner_key=mkm_access_token,
    resource_owner_secret=mkm_token_secret,
)

r = session.get(url)
print(r)

当我查看调试信息时,一切似乎都很好(当然除了403响应):

DEBUG:requests_oauthlib.oauth1_auth:Signing request <PreparedRequest [GET]> using client <Client nonce=None, signature_method=HMAC-SHA1, realm=None, encoding=utf-8, timestamp=None, resource_owner_secret=****, decoding=utf-8, verifier=None, signature_type=AUTH_HEADER, rsa_key=None, resource_owner_key=LQj2rUwOFUJsmuJvCTlny1UzGZSXzHjo, client_secret=****, callback_uri=None, client_key=B7VI9Qg2xh855WtR>
DEBUG:requests_oauthlib.oauth1_auth:Including body in call to sign: False
DEBUG:oauthlib.oauth1.rfc5849:Collected params: [(u'oauth_nonce', u'87129670621454425921416648590'), (u'oauth_timestamp', u'1416648590'), (u'oauth_consumer_key', u'B7VI9Qg2xh855WtR'), (u'oauth_signature_method', u'HMAC-SHA1'), (u'oauth_version', u'1.0'), (u'oauth_token', u'LQj2rUwOFUJsmuJvCTlny1UzGZSXzHjo')]
DEBUG:oauthlib.oauth1.rfc5849:Normalized params: oauth_consumer_key=B7VI9Qg2xh855WtR&oauth_nonce=87129670621454425921416648590&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1416648590&oauth_token=LQj2rUwOFUJsmuJvCTlny1UzGZSXzHjo&oauth_version=1.0
DEBUG:oauthlib.oauth1.rfc5849:Normalized URI: https://sandbox.mkmapi.eu/ws/v1.1/account
DEBUG:oauthlib.oauth1.rfc5849:Base signing string: GET&https%3A%2F%2Fsandbox.mkmapi.eu%2Fws%2Fv1.1%2Faccount&oauth_consumer_key%3DB7VI9Qg2xh855WtR%26oauth_nonce%3D87129670621454425921416648590%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1416648590%26oauth_token%3DLQj2rUwOFUJsmuJvCTlny1UzGZSXzHjo%26oauth_version%3D1.0
DEBUG:oauthlib.oauth1.rfc5849:Signature: 291LTesHZR6W4bjZ1NqSW5hEgoM=
DEBUG:oauthlib.oauth1.rfc5849:Encoding URI, headers and body to utf-8.
DEBUG:requests_oauthlib.oauth1_auth:Updated url: https://sandbox.mkmapi.eu/ws/v1.1/account
DEBUG:requests_oauthlib.oauth1_auth:Updated headers: {'Accept': '*/*', 'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Authorization': 'OAuth oauth_nonce="87129670621454425921416648590", oauth_timestamp="1416648590", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="B7VI9Qg2xh855WtR", oauth_token="LQj2rUwOFUJsmuJvCTlny1UzGZSXzHjo", oauth_signature="291LTesHZR6W4bjZ1NqSW5hEgoM%3D"', 'User-Agent': 'python-requests/2.4.3 CPython/2.7.8 Darwin/14.0.0'}
DEBUG:requests_oauthlib.oauth1_auth:Updated body: None
INFO:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): sandbox.mkmapi.eu
DEBUG:requests.packages.urllib3.connectionpool:"GET /ws/v1.1/account HTTP/1.1" 403 None

这不是身份验证详细信息的问题,当您请求专用应用程序API访问时,这些问题会在帐户配置文件页面上提供,因为这些详细信息可以正常使用网站提供的PHP示例:https://www.mkmapi.eu/ws/documentation/API:Auth_libcurl

当我浏览网站的文档时,似乎没有什么异常:https://www.mkmapi.eu/ws/documentation/API:Auth_Overview

老实说,我不知道从哪里开始......

3 个答案:

答案 0 :(得分:4)

我意识到上面的代码requests_oauthlib并没有像文档中那样构建标题,所以我最终再次发明了轮子并自己构建了标题,遵循所概述的步骤在文档中:https://www.mkmapi.eu/ws/documentation/API:Auth_OAuthHeader

以下脚本不是很漂亮,但它确实起作用。

import requests
from urllib import quote_plus as rawurlencode
import time
import string
import random
import operator
from hashlib import sha1
from hmac import new as hmac


def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
    return ''.join(random.choice(chars) for _ in range(size))

# personal Info - taken from https://www.mkmapi.eu/ws/documentation/API:Auth_Overview
mkmAppToken = 'bfaD9xOU0SXBhtBP'
mkmAppSecret = 'pChvrpp6AEOEwxBIIUBOvWcRG3X9xL4Y'
mkmAccessToken = 'lBY1xptUJ7ZJSK01x4fNwzw8kAe5b10Q'
mkmAccessSecret = 'hc1wJAOX02pGGJK2uAv1ZOiwS7I9Tpoe'

# Url to access on mkm
# note that this deviates from the example in the header documentation (https://www.mkmapi.eu/ws/documentation/API:Auth_OAuthHeader) which uses
#accessUrl = 'https://www.mkmapi.eu/ws/v1.1/account'
accessUrl = 'https://www.mkmapi.eu/ws/v1.1/output.json/account'

#Method for access

MyMethod = "GET"

baseString = MyMethod + "&" + rawurlencode(accessUrl) + "&"

# create a random string
# the documentation in https://www.mkmapi.eu/ws/documentation/API:Auth_OAuthHeader uses
#nonce = 53eb1f44909d6
nonce = id_generator(8)

# what time is it?
# the documentation in https://www.mkmapi.eu/ws/documentation/API:Auth_OAuthHeader uses
#now = 1407917892

now = str(int(time.time()))

MyOauthmethod = "HMAC-SHA1"
MyOauthver = "1.0"

# define Parameters and values, order doesn't matter
paramDict ={"oauth_consumer_key":mkmAppToken, "oauth_token" :mkmAccessToken, "oauth_nonce":nonce, "oauth_timestamp":now, "oauth_signature_method":MyOauthmethod, "oauth_version":MyOauthver}

# sorting of parameters is done here
sorted_paramDict = sorted(paramDict.items(), key=operator.itemgetter(0))

#collect the full parameters string
paramStr = ''

for kv in sorted_paramDict:
    paramStr = paramStr + kv[0] + "=" + kv[1] + "&"


# and get rid of the trailing ampersand
paramStr = paramStr[:-1]


#concatenate request and oauth parameters
baseString = baseString + rawurlencode(paramStr)

# concatenate both keys
signingKey = rawurlencode(mkmAppSecret) + "&" + rawurlencode(mkmAccessSecret)
# and create a hased signature with the key and the baseString
Signature = hmac(signingKey, baseString, sha1).digest().encode('base64')[:-1]


# construct the header from the parameters and the URL and the signature
MyHeader = 'OAuth ' + 'realm="' + accessUrl + '", ' 

for kv in sorted_paramDict:
    MyHeader += kv[0] + '="' + kv[1] + '",'

MyHeader += 'oauth_signature="' + Signature +'"'

headers = {'Authorization': MyHeader}

# and now requests can do its magic (pun intended)

r = requests.get(accessUrl, headers=headers)

outjson = r.json()

答案 1 :(得分:3)

您需要提供领域作为OAuth1Session的参数,如下所示:

session = requests_oauthlib.OAuth1Session(
    mkm_app_token,
    client_secret=mkm_app_secret,
    resource_owner_key=mkm_access_token,
    resource_owner_secret=mkm_token_secret,
    realm=url
)

我过去遇到过的其他事情包括mkm api没有(或者至少没有)接受URI转义参数的事实,所以你可能需要对它们进行转换。

答案 2 :(得分:0)

对于任何在2020年读书的人来说,都不需要重新发明轮子,只需将Oauth标头和参数传递给请求,这是metaproducts / find的示例:

import requests
from requests_oauthlib import OAuth1
import json 
import passwords

card_name = 'Tarmogoyf'

output = 'output.json'
base_url = 'https://api.cardmarket.com/ws/v2.0/' + output + '/'

url = base_url + 'metaproducts/find'
params={'search': card_name}

headeroauth = OAuth1(
    realm = url,
    client_key = passwords.mkm_app_token,
    client_secret = passwords.mkm_app_secret,
    resource_owner_key = passwords.mkm_access_token,
    resource_owner_secret = passwords.mkm_token_secret,
)

response = requests.get(
    url,
    params,
    auth = headeroauth
    )


if (response.ok == True):
    json_response = response.json()
    print(json.dumps(json_response, indent=4, sort_keys=True))
else:
    print(str(response.status_code) + " " + response.reason)
    exit()

字符串的/output.json/部分使输出JSON代替XML