新浪微博OAuth详解以Python为例

简介:

让我先吐槽一下新浪微博的那个 OAuth 文档,写得就像个锤子一样!

1. 什么是OAuth

OAuth 是一套认证形式,并被逐渐推荐为一套标准,它的老家在 http://oauth.net 。

OAuth 实现的是一套三方委托认证的模式。

举例来说,有人想知道你新浪微博上的所有粉丝都有哪些,而你也愿意让他知道。但是,这里有一个问题,如果你直接把账号和密码告诉这个人的话,你可能会觉得很不安全,你只想把有限的东西给这个人,而不是把账号和密码都交出来。

于是,可以使用这样的一种方式,这个人去找新浪要你的粉丝资料,新浪就问你,你愿意把你的资料给这个人么?你说愿意。好,新浪就把你的资料给这个人了,只是给这个人。于是,这个人在你的授权下得到了你的粉丝资料,但是你并没有把账号和密码泄漏出去。

整个过程大概如下图所示:

                               4.Here you are
                          ---------------------
                          |                   |
                          |                   |
                 -------------                |
        2.argee? |           |  1.request     |
       --------- |   SINA    | <---------     |
       |         |           |          |     |
       |         -------------          |     |
       v              ^                 |     v
-------------         |             -------------
|           |         |             |           |
|    YQ     |----------             |    ZYS    |
|           |  3.Yes                |           |
-------------                       -------------

记住这里的 4 个过程:

request
argee?
Yes
Here you are

从图中可以看出,整个过程中 SINA 都扮演着一个中间者的作用, ZYS 和 YQ 通过与 SINA 的参数传递实现授权访问。

上面的前 3 个过程对应着 3 个新浪的认证 URL (最后一个是具体的应用 API 了):

这 3 个 URL 的作用是这样的:

  • ZYS 找到 SINA 说,等下 YQ 会过来,我要拿 YQ 的粉丝数据。通过参数的传递 ZYS 向 SINA 标明了自己的身份。SINA 说,我知道了,然后 SINA 会给 ZYS 一对request_token 和 request_secret 。
  • YQ 过来了,问 SINA 说是不是 ZYS 要拿我的粉丝数据啊,然后把 ZYS 私下给的request_token 和 request_secret 给 SINA 看了,并同意 ZYS 拿她的数据,这时 SINA 还给了 YQ 一个 verifier 。YQ 把 verifier 拿给了 ZYS ,表示她已经在 SINA 那里打过招呼了。
  • ZYS 拿着 request_token , request_secret , verifier 这三样东西,找到 SINA,说明他已经取得了 YQ 的授权。此时, SINA 给了 ZYS 一对 access_token 和access_secret 。之后,凭着这对东西, ZYS 就可以从 SINA 那里取得 YQ 的粉丝数据了。(实际上, request_secret 和 access_secret 是相同的)
  • 整个过程就是这样的,除了上面提到的几个参数,还有一组 APP_KEY 和 APP_SECRET ,是我们在新浪微博开放平台上申请应用时,被分配的。 我们关注的几个传递来传递去的参数有:

    • APP_KEY, APP_SECRET
    • request_token, request_secret
    • verifier
    • access_secret, access_secret

下面开始实战。

2. 准备工作

首先,需要去新浪微博的开放平台 http://open.t.sina.com.cn 上注册用户,然后创建一个应用。在应用的页面,你可以找到一对 APP_KEY 和 APP_SECRET 。

2.1. request_token

现在我们开始第一步,也是最难的一步。

OAuth 的认证过程无非就是通过 HTTP 协议把几个参数传递一下,没有什么复杂的东西。但是,因为文档描述问题,这些参数应该怎么包装,签名应该如何做,如果不得要领是很烦人的事。我们在这一步把参数的包装和签名计算方法搞定,之后的两步就水道渠成了。

OAuth 的认证参数通常是放到头部信息中传递的(当然,也可以放到 URL 中),这个头部信息如何包装我们之后会细细介绍。

参看官方文档 http://open.weibo.com/wiki/index.php/Oauth/request_token ,得知请求 request_token 时需要的参数有:

  • oauth_consumer_key: 创建应用时生成的 APP_KEY 。
  • oauth_signature_method: 签名方法,使用 HMAC-SHA1 。
  • oauth_timestamp: 时间戳。 int(time.time()) 就可以了。
  • oauth_nonce: 单次值,一个随机字符串,防止重复攻击。我使用 uuid.uuid4().hex 。
  • oauth_version: OAuth协议版本。填写 1.0 。
  • oauth_signature: 签名值,是由根据上面的 5 个参数生成的 Base String 经 HMAC-SHA1 算法计算得出。

上面的参数当中,除了最后一个 oauth_signature ,其它的都应该很清楚

2.2. oauth_signature的计算方法

oauth_signature 是通过 HMAC-SHA1 算法,处理一个叫 Base String 的字符串,最后取 base64 编码得到的。而 Base String 字符串是由访问方法,访问 URL ,及前面的 5 个参数拼接而成。

假设访问方法是 GET ,要访问的 URL 是http://api.t.sina.com.cn/oauth/request_token ,同时假设这 5 个参数为:

  • oauth_consumer_key: 1234567
  • oauth_version: 1.0
  • oauth_timestamp: 1307980836
  • oauth_nonce: xxoo
  • oauth_signature_method: HMAC-SHA1
  • method = 'GET'
  • url = 'http://api.t.sina.com.cn/oauth/request_token'
  • p = ''
  • base_string = '%s&%s&%s' % (method, quote(url, safe=''), p)

最后的 Base String 即是使用 & 连接这三组数据, url 需要进行 URL 编码( / 也要编码,所以要加一个 safe='' )。我们重点说 p 如何得到。

p 由上面的 5 个参数 按序 拼接而成。

from urllib import urlencode, quote

params = [
    ('oauth_consumer_key', '1234567'),
    ('oauth_version', '1.0'),
    ('oauth_timestamp', '1307980836'),
    ('oauth_nonce', 'xxoo'),
    ('oauth_signature_method', 'HMAC-SHA1'),
]
params.sort()

p = quote(urlencode(params))

简单说,就是排序后进行 URL 编码再进行第二次 URL 编码。于是:

from urllib import urlencode, quote

method = 'GET'
url = 'http://api.t.sina.com.cn/oauth/request_token'
params = [
    ('oauth_consumer_key', '1234567'),
    ('oauth_version', '1.0'),
    ('oauth_timestamp', '1307980836'),
    ('oauth_nonce', 'xxoo'),
    ('oauth_signature_method', 'HMAC-SHA1'),
]
params.sort()

p = quote(urlencode(params))

base_string = '%s&%s&%s' % (method, quote(url, safe=''), p)

-------------
GET&http%3A%2F%2Fapi.t.sina.com.cn%2Foauth%2Frequest_token&oauth_consumer
_key%3D1234567%26oauth_nonce%3Dxxoo%26oauth_signature_method%3DHMAC
-SHA1%26oauth_timestamp%3D1307980836%26oauth_version%3D1.0

得到 Base String 后,需要使用 HMAC-SHA1 算法对其进行处理(HMAC 算法需要一个 KEY ,在实际认证中使用 APP_SECRET 或者 *_secret ),在 Python 中有现成的模块可以使用:

import hmac, hashlib

KEY = 'abc'

h = hmac.new(KEY, base_string, hashlib.sha1)
s = h.digest()
signature = quote(s.encode('base64').rstrip())
#gA6Eo8xQgEgHMbaOdIdXFwbH/1Y%3D

最后的结果,就是我们需要的签名值。

2.3. 完整的例子

#! /usr/bin/python
# -*- coding: utf-8 -*-

from urllib import quote, urlencode
import urllib2
import time
import uuid
import hmac, hashlib

def get_token():
    URL = 'http://api.t.sina.com.cn/oauth/request_token'
    APP_KEY = '' #写自己的
    APP_SECRET = ''

    params = [
        ('oauth_consumer_key', APP_KEY),
        ('oauth_nonce', uuid.uuid4().hex),
        ('oauth_signature_method', 'HMAC-SHA1'),
        ('oauth_timestamp', int(time.time())),
        ('oauth_version', '1.0'),
    ]

    params.sort()

    p = 'GET&%s&%s' % (quote(URL, safe=''), quote(urlencode(params)))
    signature = hmac.new(APP_SECRET + '&', p, hashlib.sha1).digest().encode('base64').rstrip()

    params.append(('oauth_signature', quote(signature)))

    h = ', '.join(['%s="%s"' % (k, v) for (k, v) in params])

    r = urllib2.Request(URL, headers={'Authorization': 'OAuth realm="", %s' % h})

    data = urllib2.urlopen(r).read()
    token, secret = [pair.split('=')[1] for pair in data.split('&')]

    return token, secret

if __name__ == '__main__':
    print get_token()

这一步过后,我们就获得了 request_token 和 request_secret 。

2.4. authorize

这一步做得事情就简单多了,只需要把上一步获取到的 request_token 作为 oauth_token 这个参数添加到 URL http://api.t.sina.com.cn/oauth/authorize 后面进行访问就可以了。

新浪微博的系统会自动作用户的登陆处理(或者可以传入 userId 和 passwd 直接获取到verifier ),然后用户可以选择是否授权给你的应用。确认后,你可以得到 verifier 用于下一步。

参见官方的文档 http://open.weibo.com/wiki/index.php/Oauth/authorize ,除了oauth_token 这个必须的参数以个,还有几个可选的参数:

  • oauth_callback: 用户确认授权后,重定向到的 URL 地址, verifier 和 oauth_token 会作为参数跟在此 URL 后面。
  • display: 页面调用方式。
  • userId: 账户名。
  • passwd: 密码。

其中 userId 和 passwd 是和 oauth_callback=json|xml 配合使用的。它直接返回verifier ,没有确认授权页面。

假设上一步我们得到的 request_token 是 808cb0645284a4e0995fbcc7ac29e381 ,那么最简单的一个 URL 就是

http://api.t.sina.com.cn/oauth/authorize?oauth_token=808cb0645284a4e0995fbcc7ac29e381

在浏览器当中直接访问这个地址即可。新浪微博会让你登陆并确认授权。之后会在页面中显示verifier 。

如果是 web 应用的话,一般我们会使用回调地址的方式,使用 oauth_callback 传递地址:

http://api.t.sina.com.cn/oauth/authorize?oauth_token=808cb0645284a4e0995fbcc7ac29e381&oauth_callback=http%3A%2F%2Flocalhost%3A8080%2F

上面的 URL 中,我们把 http://localhost:8080/ 进行 URL 编码后放到 oauth_callback参数当中。

访问并授权后,页面会重定向到:

http://localhost:8080/?oauth_token=d18fbed6c40ba7b961aa860087b427e7&oauth_verifier=706286

这里有 oauth_token 和 oauth_verifier ,你可以在后端处理它们了。

经过这一步,我们现在手头上有 request_token , request_secret , verifier 这三个东西了。下一步会用到它们。

2.5. access_token

这一步我们使用手中的 request_token , request_secret , verifier 去换取一对access_token 和 access_secret 。整体上和第一步的操作相同。就是计算签名值和包装参数。前面是使用的 GET 方法,这里要使用 POST 方法了。

参见官方的文档 http://open.weibo.com/wiki/index.php/Oauth/access_token ,需要传递的 OAuth 参数有:

  • oauth_consumer_key: APP_KEY
  • oauth_token: 我们手中的 request_token
  • oauth_signature_method: 签名方法,使用 HMAC-SHA1
  • oauth_timestamp: 时间戳
  • oauth_nonce: 单次值
  • oauth_version: OAuth协议版本。写 1.0
  • oauth_verifier: 我们手中的 verifier
  • oauth_signature: 签名值,是由根据上面的几个参数生成的 Base String 经 HMAC-SHA1 算法计算得出。

这里计算 oauth_signature 时不同的地方就是要使用 request_secret 作为 HMAC 的 KEY 的一部分:

前面的是这样:

signature = hmac.new(APP_SECRET + '&', p, hashlib.sha1).digest().encode('base64').rstrip()

现在需要这样:

signature = hmac.new(APP_SECRET + '&' + request_token, p,
                     hashlib.sha1).digest().encode('base64').rstrip()

完整的代码如下:

#! /usr/bin/python
# -*- coding: utf-8 -*-

from urllib import quote, urlencode
import urllib2
import time
import uuid
import hmac, hashlib

def get_access_token(token, secret, verifier):
    URI = 'http://api.t.sina.com.cn/oauth/access_token'
    APP_KEY = '' #写自己的
    APP_SECRET = ''

    headers = [
        ('oauth_consumer_key', APP_KEY),
        ('oauth_nonce', uuid.uuid4().hex),
        ('oauth_signature_method', 'HMAC-SHA1'),
        ('oauth_timestamp', int(time.time())),
        ('oauth_version', '1.0'),
        ('oauth_token', token),
        ('oauth_verifier', verifier),
        ('oauth_token_secret', secret),
    ]

    headers.sort()

    p = 'POST&%s&%s' % (quote(URI, safe=''), quote(urlencode(headers)))
    signature = hmac.new(APP_SECRET + '&' + secret, p,
                         hashlib.sha1).digest().encode('base64').rstrip()

    headers.append(('oauth_signature', quote(signature)))

    h = ', '.join(['%s="%s"' % (k, v) for (k, v) in headers])

    r = urllib2.Request(URI, headers={'Authorization': 'OAuth realm="", %s' % h})

    data = urllib2.urlopen(r, data='').read()
    token, secret, user_id = [pair.split('=')[1] for pair in data.split('&')]

    return token, secret, user_id

if __name__ == '__main__':
    print get_access_token('0a426d1b8695df7888c0b79d77c2071c',
                           '77764447cbdd856463b3198c935bad41',
                           '601738')

上面代码中,调用 get_access_token 函数的三个参数都在上一步获取到了的。

访问之后,你可以得到一个新的 access_token ( request_secret 没有变的,当然,之后我们可以把它改叫做 access_secret ),之后我们就使用它去访问各个需要授权的 API 接口了。

3. 获取授权者的个人信息

现在我们手头上有 access_token 和 access_secret 了,作为示例,我们去获取一下授权者的个人信息。

查看官方文档 http://open.weibo.com/wiki/index.php/Account/verify_credentials,这个验证用户身份的 API 可以获取用户信息。

像之前的认证过程一样,需要在头部中带上 OAuth 的那 7 个参数:

  • oauth_consumer_key: APP_KEY
  • oauth_token: 我们手中的 access_token
  • oauth_signature_method: 签名方法,使用 HMAC-SHA1
  • oauth_timestamp: 时间戳
  • oauth_nonce: 单次值
  • oauth_version: OAuth协议版本。写 1.0
  • oauth_signature: 签名值,是由根据上面的几个参数生成的 Base String 经 HMAC-SHA1 算法计算得出。

应该说的前面已经说过了,直接上代码吧:

#! /usr/bin/python
# -*- coding: utf-8 -*-

from urllib import quote, urlencode
import urllib2
import time
import uuid
import hmac, hashlib

def get_info(token, secret):
    URI = 'http://api.t.sina.com.cn/account/verify_credentials.json'
    APP_KEY = '' #写自己的
    APP_SECRET = ''

    headers = [
        ('oauth_consumer_key', APP_KEY),
        ('oauth_nonce', uuid.uuid4().hex),
        ('oauth_signature_method', 'HMAC-SHA1'),
        ('oauth_timestamp', int(time.time())),
        ('oauth_version', '1.0'),
        ('oauth_token', token)
    ]

    headers.sort()

    p = 'POST&%s&%s' % (quote(URI, safe=''), quote(urlencode(headers)))
    signature = hmac.new(APP_SECRET + '&' + secret, p,
                         hashlib.sha1).digest().encode('base64').rstrip()

    headers.append(('oauth_signature', quote(signature)))

    h = ', '.join(['%s="%s"' % (k, v) for (k, v) in headers])

    r = urllib2.Request(URI, data='', headers={'Authorization': 'OAuth realm="", %s' % h})

    data = urllib2.urlopen(r).read()
    return data

if __name__ == '__main__':
    print get_info('97de3e2422c2b5fe4328d6cdc1ac5597', '2563a0ac36baecbbb7d93a4987d899df')

代码中调用 get_info 函数需要的两个参数就是前面我们已经取得的 access_token 和access_secret 。


目录
相关文章
|
2月前
|
JSON 安全 数据安全/隐私保护
Python认证新风尚:OAuth遇上JWT,安全界的时尚Icon👗
【10月更文挑战第2天】在当今互联网世界中,数据安全与隐私保护日益重要。Python 作为广泛应用于 Web 开发的语言,其认证机制也不断进化。OAuth 2.0 和 JSON Web Tokens (JWT) 成为当前最热门的安全认证方案,不仅保障数据安全传输,还简化了用户认证流程。本文将介绍 Python 如何结合 OAuth 2.0 和 JWT 打造安全高效的认证体系。
41 3
|
1月前
|
JSON 安全 数据安全/隐私保护
Python认证新风尚:OAuth遇上JWT,安全界的时尚Icon👗
在当今互联网世界中,数据安全和隐私保护至关重要。Python 作为 Web 开发的主流语言,其认证机制也在不断进步。OAuth 2.0 和 JSON Web Tokens (JWT) 是当前最热门的安全认证方案,不仅保障数据安全传输,还简化用户认证流程。本文介绍如何在 Python 中结合 OAuth 2.0 和 JWT,打造一套既安全又高效的认证体系。通过 Flask-HTTPAuth 和 PyJWT 等库,实现授权和验证功能,确保每次请求的安全性和便捷性。
38 3
|
1月前
|
JSON 安全 数据安全/隐私保护
告别密码泄露!Python OAuth与JWT双剑合璧,守护你的数字资产💰
本文探讨了在Python环境中利用OAuth 2.0和JSON Web Tokens (JWT) 提高系统安全性的方法。OAuth 2.0是一种开放标准授权协议,通过用户授权和令牌颁发来保护资源访问。JWT则是一种紧凑、自包含的认证方式,用于安全传输信息。文章详细介绍了如何使用Flask-OAuthlib实现OAuth 2.0认证,以及使用PyJWT生成和验证JWT。结合这两种技术,可以构建出既安全又高效的认证体系,为数据安全提供双重保障。
26 3
|
1月前
|
JSON 安全 数据安全/隐私保护
Python安全守护神:OAuth与JWT,让黑客望而却步的魔法阵🧙‍♂️
在网络世界中,数据安全至关重要。本文介绍了如何在Python环境中使用OAuth 2.0和JSON Web Tokens (JWT) 构建安全的认证系统。OAuth 2.0是一种开放标准授权协议,允许客户端在不暴露用户凭证的情况下访问资源。JWT则是一种轻量级的数据交换格式,用于在各方之间安全地传输信息。结合两者,可以构建出既安全又高效的认证体系。文章通过Flask-OAuthlib和PyJWT库的示例代码,详细展示了实现过程。
45 2
|
2月前
|
JSON 安全 数据安全/隐私保护
深度剖析:Python如何运用OAuth与JWT,为数据加上双保险🔐
【10月更文挑战第10天】本文介绍了OAuth 2.0和JSON Web Tokens (JWT) 两种现代Web应用中最流行的认证机制。通过使用Flask-OAuthlib和PyJWT库,详细展示了如何在Python环境中实现这两种认证方式,从而提升系统的安全性和开发效率。OAuth 2.0适用于授权过程,JWT则简化了认证流程,确保每次请求的安全性。结合两者,可以构建出既安全又高效的认证体系。
49 1
|
2月前
|
JSON 安全 数据安全/隐私保护
深度剖析:Python如何运用OAuth与JWT,为数据加上双保险🔐
【10月更文挑战第2天】当讨论Web应用安全时,认证与授权至关重要。OAuth 2.0 和 JSON Web Tokens (JWT) 是现代Web应用中最流行的两种认证机制。OAuth 2.0 是一种开放标准授权协议,允许资源拥有者授予客户端访问资源的权限,而不需直接暴露凭据。JWT 则是一种紧凑、URL 安全的信息传输方式,自我包含认证信息,无需服务器查询数据库验证用户身份。在 Python 中,Flask-OAuthlib 和 PyJWT 分别用于实现 OAuth 2.0 和 JWT 的功能。结合两者可构建高效且安全的认证体系,提高安全性并简化交互过程,为数据安全提供双重保障。
37 7
|
2月前
|
JSON 安全 数据安全/隐私保护
Python安全守护神:OAuth与JWT,让黑客望而却步的魔法阵🧙‍♂️
【10月更文挑战第2天】在网络世界中,数据安全至关重要。本文以教程形式介绍如何在Python环境中使用OAuth 2.0和JSON Web Tokens (JWT) 构建安全认证系统。OAuth 2.0 作为一种开放标准授权协议,允许客户端安全访问资源;JWT 则用于安全传输信息。二者结合可构建高效且安全的认证体系。文中详细介绍了OAuth 2.0 的工作流程及如何使用Flask-OAuthlib实现认证;并通过PyJWT库展示了JWT的生成与验证方法。最后探讨了两者结合使用的具体实践,旨在为开发者提供全面的认证解决方案。随着技术发展,这两种技术将继续在认证领域发挥重要作用。
40 4
|
2月前
|
JSON 安全 数据安全/隐私保护
告别密码泄露!Python OAuth与JWT双剑合璧,守护你的数字资产💰
【10月更文挑战第2天】密码泄露是互联网安全的重大隐患。为了解决这一问题,开发人员采用更安全的认证机制,如 OAuth 2.0 和 JSON Web Tokens (JWT),以保护用户数字资产。OAuth 2.0 作为一种开放标准授权协议,允许资源拥有者向客户端授予访问权限而不必暴露凭证;JWT 则是一种用于安全传输信息的紧凑格式,能够在各方间传递自包含认证信息。
42 3
|
3月前
|
JSON 安全 数据安全/隐私保护
实战指南:Python中OAuth与JWT的完美结合,构建安全认证防线
【9月更文挑战第9天】当今互联网应用的安全性至关重要,尤其在处理用户数据和个人隐私时。OAuth 和 JWT 是两种广泛使用的认证机制,各具优势。本文探讨如何在 Python 中结合 OAuth 和 JSON Web Tokens (JWT) 构建安全可靠的认证系统。OAuth 允许第三方应用获取有限访问权限而不暴露用户密码;JWT 则是一种轻量级数据交换格式,用于安全传输信息。结合使用这两种技术,可以在确保安全性的同时简化认证流程。
36 4
|
3月前
|
JSON 安全 数据安全/隐私保护
告别密码泄露!Python OAuth与JWT双剑合璧,守护你的数字资产💰
【9月更文挑战第5天】密码泄露是互联网安全的重大隐患。为了解决这一问题,开发者们采用了更为安全的认证机制,如OAuth 2.0和JSON Web Tokens (JWT),以保护用户的数字资产。OAuth 2.0通过授权协议允许资源拥有者授予客户端访问权限而不暴露凭证;JWT则提供了一种紧凑且安全的信息传输方式,使得认证信息自包含于令牌中。
94 8