我对 Flask 和 OAuth 都不熟悉,所以对照了 Flask-OAuthlib 官方的 Twitter 例子,想仿写一个饭否应用,进行 OAuth 认证后通过网页发送消息。
但是我写的程序执行到 oauthorized()
中 authorized_response()
这个函数后,返回的却一直是 None
。我调试了一晚上,还是不知道自己错在什么地方了,以下是我的 fanfou.py
文件:
from flask import Flask, session, redirect, url_for, request, render_template, flash
from flask_oauthlib.client import OAuth, OAuthException
app = Flask(__name__)
app.debug = True
app.secret_key = 'AA0Zr98j/3yXR~XHH!jmN]LWX/,?RT'
oauth = OAuth(app)
fanfou = oauth.remote_app(
'fanfou',
base_url='http://api.fanfou.com/',
request_token_url='http://fanfou.com/oauth/request_token',
access_token_url='http://fanfou.com/oauth/access_token',
authorize_url='http://fanfou.com/oauth/authorize',
consumer_key='这里是我的consumer_key',
consumer_secret='这里是我的consumer_secret',
)
@fanfou.tokengetter
def get_fanfou_token():
return session.get('fanfou_token')
@app.route('/')
def index():
if 'fanfou_token' not in session:
flash('Unable to load fanfou_oauth.')
return render_template('index.html')
@app.route('/tweet', methods=['POST'])
def tweet():
status = request.form['tweet']
if not status:
return redirect(url_for('index'))
resp = fanfou.post('statuses/update.json', data={
'status': status
})
if resp.status == 403:
flash('Your tweet was too long.')
elif resp.status == 401:
flash('Authorization error with Fanfou.')
else:
flash('Successfully!')
return redirect(url_for('index'))
@app.route('/login')
def login():
callback = url_for('oauthorized', next=request.args.get('next') or request.referrer or None, _external=True)
return fanfou.authorize(callback=callback)
@app.route('/logout')
def logout():
session.pop('fanfou_token', None)
return redirect(url_for('index'))
@app.route('/oauthorized')
def oauthorized():
next_url = request.args.get('next') or url_for('index')
resp = fanfou.authorized_response()
# 问题在此,总是返回 None
if resp is None:
flash('You denied the request to sign in.')
if isinstance(resp, OAuthException):
flash('Access denied: %s' % resp.message)
session['fanfou_token'] = resp
return redirect(next_url)
if __name__ == '__main__':
app.run()
整个项目完整的版本可以查看这里。
饭否使用的是 OAuth 1.0,其文档在 https://github.com/FanfouAPI/FanFouAPIDoc/wiki/Oauth。我在饭否应用信息中设置的 Callback URL 是 http://127.0.0.1:5000/oauthorized
。
研究大半天我头都要炸了……如果我对某些概念的理解存在偏差,请指出…… _(:з」∠)_
1
raptor 2015-03-16 14:17:25 +08:00 1
不知道flask_oauthlib是怎么实现的,我用reqeusts自己做过一个实现是没问题的: https://bitbucket.org/raptorz/restclient。
饭否似乎并不使用应用信息中注册的callback,而是使用授权页面(request_token)时传入的callback参数,另外服务器时间错误也会导致授权失败。 |
2
mimzy OP @raptor 感谢猛禽大大,回去我再看看。
中午试了下渣浪微博的例子成功了,饭否就不行。 关于 Callback URL,用这个库时只要我填上就能跳转回来,不填的话就直接留在授权成功页面了。这个我也再研究研究。 |
3
raptor 2015-03-17 08:56:44 +08:00 1
@mimzy 那我大概知道了。因为饭否在响应时默认不使用code项,即在调用access_token时不需要传入verify_code参数,所以在callback时也不会提供code,这个库估计对此没有判断,只要callback时没有code就自动出错了。这种情况只能修改库代码了
|
5
mimzy OP @raptor 时隔半年多我又重新研究了一遍,结果发现猛师傅说得完全正确啊!这个库通过判断 oauth_verifier 这个东西调用响应方法,但是饭否没传这个值,所以只好返回 None 了。我简单改了下库已经能用了,再次感谢猛师傅~
|
7
mimzy OP 最终解决反感:不修改 Flask-OAuthlib 这个库,而是在饭否的 Callback URL 末尾添加 ?oauth_verifier=0 ,这样传回来地址的时候 request.args 里就有了 oauth_verifier 这一项。 oauth_verifier 对于能否发消息无关紧要,但关系到 Flask-OAuthlib 判断应该调用 oauth1 还是 oauth2 的方法。
|
8
mimzy OP 反感 -> 方案
|