站内应用是直接嵌入到新浪微博的一种应用,用户在使用站内应用时,仍访问新浪微博的网站,而具体的站内应用则以iframe的形势嵌入页面。由于这种应用不同于第三方网站,不能通过新浪微博的授权页跳转实现授权,所以,获得用户授权稍有不同。
创建站内应用时,首先,需要申请站内应用,除了App ID,App Secret外,还有新浪微博分配的站内应用的地址和应用的实际地址,即iframe加载的网站地址。以下代码是站内应用apps.weibo.com/irunning的常量定义。代码如下:
_APP_ID = '12345'
_APP_SECRET = 'abc123xyz'
_APP_URL = 'http://apps.weibo.com/irunning'
_SERVER_URL = 'http://weiborun.sinaapp.com/'
当用户在新浪微博网站内访问http://apps.weibo.com/irunning时,新浪微博会发送POST请求至内嵌的iframe,因此,我们的后台服务http://weiborun.sinaapp.com/会收到该POST请求,并获取signed_request参数,我们需要从signed_request中获取加密的参数。代码如下:
@post('/')
def index():
data = _parse_signed_request(ctx.request['signed_request']))
if data is None:
# 用户未授权,返回授权页:
raise seeother('/auth.html')
# 用户已授权,获取OAuth token:
access_token = data['oauth_token']
expires = data['expires']
client = _create_client()
client.set_access_token(access_token, expires)
def _parse_signed_request(sr):
def _b64_normalize(s):
' 还原Base64编码字符串 '
appendix = '=' * (4 - len(s) % 4)
return s.replace('-', '+').replace('_', '/') + appendix
sr = str(signed_request)
logging.info('parse signed request: %s' % sr)
enc_sig, enc_payload = sr.split('.', 1)
# 获得Digest:
sig = base64.b64decode(_b64_normalize(enc_sig))
# 获得JSON数据:
data = _parse_json(base64.b64decode(_b64_normalize(enc_payload)))
if data['algorithm'] != u'HMAC-SHA256':
return None
# 计算Digest:
expected_sig = hmac.new(self.client_secret, enc_payload, hashlib.sha256).digest();
# 与新浪微博发送的Digest对比是否一致:
if expected_sig==sig:
if data.get('oauth_token', None) is None:
return None
return data
return None
新浪微博传入的signed_request字符串参数通过解码后拿到HMAC-SHA256签名和原始JSON数据,此时,我们需要根据App Secret自己计算出签名,并与新浪微博传入的签名对比,若一致,则说明JSON数据有效,否则,说明数据是第三方伪造的。由于App Secret只有我们的站内应用和新浪微博持有,因此,第三方是无法伪造签名的。
验证了签名后,即可从JSON数据中获取oauth_token参数。若oauth_token参数为空,则表示用户未授权,我们就给用户显示授权页auth.html,授权页源码如下,主要通过一个JavaScript调用弹出授权框给用户。
<html>
<head>
<title>未授权时的页面</title>
<script src="http://tjs.sjs.sinajs.cn/t35/apps/opent/js/frames/client.js" type="text/javascript"></script>
</head>
<script>
function authLoad() {
App.AuthDialog.show({
client_id: '12345',
redirect_uri: 'http://apps.weibo.com/irunning',
height: 40
});
}
</script>
<body onload="authLoad();">
</body>
</html>
弹窗的JavaScript代码是由新浪微博提供的,效果如下:
用户可以在弹出的授权框中授权,然后,新浪微博会再次发送POST请求至站内应用的网站,此时,从signed_request参数中即可获取到oauth_token。有了oauth_token,我们就可以用SDK调用任意的API了,包括获取当前授权用户的用户信息,以判断该用户是否是第一次访问。此后的API调用与普通Web网站是一样的,这里就不再多述。
本文的站内应用地址:
http://apps.weibo.com/irunning
本文的网站源码可以从GitHub下载: