在 Python 中签署 OAuth 请求
目前我正在使用 OAuth 协议连接 Twitter API 并用 Python 编写代码。与大多数用户一样,我认为规范中最困难的部分是处理签名。
在网上寻找解决方案后,我决定使用我的自定义代码,以便更好地了解正在发生的事情。
为了其他用户的利益,我在这里发布了一个非常简单且简短的 Python 中 SHA1 签名规范的实现:
import hmac
from hashlib import sha1
from urllib import quote, urlencode
from base64 import b64encode
from urlparse import urlparse
def sign_request_sha1(url,method,data,secret=""):
pu = urlparse(urlparse(url).geturl())
normUrl = "%s://%s%s%s" % (
pu.scheme,
pu.hostname,
"" if not pu.port or {"http":80,"https":443}[pu.scheme] == pu.port else ":%d" % pu.port,
pu.path,
)
names = data.keys()
names.sort()
sig = "%s&%s&%s" % (
method.upper(),
quote(normUrl,''),
quote("&".join(["%s=%s" % (k,quote(data[k].encode('utf-8'),'')) for k in names]),''),
)
key = "%s&%s" % (quote(CONSUMER_SECRET.encode('utf-8'),''),secret)
return b64encode(hmac.new(key,sig,sha1).digest())
该函数的输入参数是:
- url:您要为特定 OAuth 请求调用的 url。
- method:这必须是“GET”或“POST”,具体取决于您要如何发出请求。
- data:包含请求所有参数的字典,包括任何自定义参数,但不包括“oauth_signature”参数(出于显而易见的原因)。
- 秘密:您在协议初始阶段收到的秘密令牌。
我用 Twitter 测试了它,它似乎有效,但我希望收到一些关于错误、改进等的评论。
最后,在这里您可以找到一段调用初始“请求令牌”阶段的代码的代码:
from random import getrandbits
from base64 import b64encode
from time import time
def twitter_request_token(req,callback,errback):
req_url="http://twitter.com:80/oauth/request_token"
data = { \
"oauth_consumer_key" : CONSUMER_KEY,
"oauth_nonce" : b64encode("%0x" % getrandbits(256))[:32],
"oauth_timestamp" : str(int(time())),
"oauth_signature_method" : "HMAC-SHA1",
"oauth_version" : "1.0",
"oauth_callback" : "http://localhost:8080/",
}
data["oauth_signature"] = sign_request_sha1(req_url,"GET",data)
谢谢。
currently I'm interfacing the Twitter API using the OAuth protocol and writing the code in Python. As most of the users out there, I think the toughest part of the specs is dealing with signatures.
After wandering around the web in search for a solution, I decided to go for my custom code, so as to have a better understanding of what is going on.
For the sake of other users, I'm posting here a very simple and short implementation of the SHA1 signature specs in Python:
import hmac
from hashlib import sha1
from urllib import quote, urlencode
from base64 import b64encode
from urlparse import urlparse
def sign_request_sha1(url,method,data,secret=""):
pu = urlparse(urlparse(url).geturl())
normUrl = "%s://%s%s%s" % (
pu.scheme,
pu.hostname,
"" if not pu.port or {"http":80,"https":443}[pu.scheme] == pu.port else ":%d" % pu.port,
pu.path,
)
names = data.keys()
names.sort()
sig = "%s&%s&%s" % (
method.upper(),
quote(normUrl,''),
quote("&".join(["%s=%s" % (k,quote(data[k].encode('utf-8'),'')) for k in names]),''),
)
key = "%s&%s" % (quote(CONSUMER_SECRET.encode('utf-8'),''),secret)
return b64encode(hmac.new(key,sig,sha1).digest())
The input parameters to the function are:
- url: the url you are going to call for the specific OAuth request.
- method: this must be "GET" or "POST" depending on how you're going to issue your request.
- data: a dictionary containing all the parameters of the requests, including any custom argument but excluding the "oauth_signature" one (for obvious reasons).
- secret: a secret token you received in the initial phase of the protocol.
I tested it with Twitter and it seems to work but I'd like to receive some comments about mistakes, improvements and so on.
Lastly, here you find a piece of code calling the code for the initial "request token" phase:
from random import getrandbits
from base64 import b64encode
from time import time
def twitter_request_token(req,callback,errback):
req_url="http://twitter.com:80/oauth/request_token"
data = { \
"oauth_consumer_key" : CONSUMER_KEY,
"oauth_nonce" : b64encode("%0x" % getrandbits(256))[:32],
"oauth_timestamp" : str(int(time())),
"oauth_signature_method" : "HMAC-SHA1",
"oauth_version" : "1.0",
"oauth_callback" : "http://localhost:8080/",
}
data["oauth_signature"] = sign_request_sha1(req_url,"GET",data)
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我对此的本能反应是如果您在代码中输入字母 AES,那么您就错了。或者,正如 Reddit 用户 khafra 最近提醒我们西西里岛的版本 :
我的意思是,我明白了。我第一次查看它时,oauth.py 没有也不给我留下深刻的印象。从那以后我们做了很多工作,看起来好多了,但似乎仍然没有测试,所以我不知道。不管怎样,无论测试与否,它被更多的人审查和使用,而不是你的代码。
但这只是我对加密代码重用问题的紧张,并不能真正帮助您弄清楚协议机制。对我来说看起来不错,但最近我对 OAuth 规范没有太多关注。
只需为
pu.port
业务使用更多线路即可;将条件if
表达式、or
表达式和{}[]
结构全部集中在一行中确实 难以阅读。如果您确实希望熟悉该协议的人进行代码审查,您最好询问 邮件列表。如果您可以为他们提供替代 API,使他们存储库中的代码对新用户更具吸引力,那么这对每个人都有好处。
My knee-jerk reaction to this is If You're Typing The Letters A-E-S Into Your Code, You're Doing It Wrong. Or, as redditor khafra recently reminded us of the Sicilian's version:
I mean, I get it. The first time I looked at it, oauth.py didn't impress me either. There's been a lot of work on it since and it's looking better, but there still appear to be no tests, so I don't know. Anyway, tests or no tests, it's been reviewed and used by more people than your code has.
But that's just me being uptight on the subject of crypto code reuse and doesn't really help you in figuring out the protocol machinery. It looks okay to me, but I haven't had my head in the OAuth spec too much lately.
Just use some more lines for that
pu.port
business; having a conditionalif
expression, anor
expression, and the{}[]
construct all in one line is really hard to read.If you really want code review by people who are familiar with the protocol, you're probably better off asking the mailing list. And if you can offer them an alternate API that will make the code in their repository more appealing to new users, that'll be good for everyone.