请教使用 Flask-OAuthlib 申请饭否 OAuth 认证,但是不返回 Access token 的问题

2015-03-16 00:45:35 +08:00
 mimzy

我对 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

研究大半天我头都要炸了……如果我对某些概念的理解存在偏差,请指出…… _(:з」∠)_

4220 次点击
所在节点    Flask
8 条回复
raptor
2015-03-16 14:17:25 +08:00
不知道flask_oauthlib是怎么实现的,我用reqeusts自己做过一个实现是没问题的: https://bitbucket.org/raptorz/restclient。

饭否似乎并不使用应用信息中注册的callback,而是使用授权页面(request_token)时传入的callback参数,另外服务器时间错误也会导致授权失败。
mimzy
2015-03-16 17:01:36 +08:00
@raptor 感谢猛禽大大,回去我再看看。

中午试了下渣浪微博的例子成功了,饭否就不行。

关于 Callback URL,用这个库时只要我填上就能跳转回来,不填的话就直接留在授权成功页面了。这个我也再研究研究。
raptor
2015-03-17 08:56:44 +08:00
@mimzy 那我大概知道了。因为饭否在响应时默认不使用code项,即在调用access_token时不需要传入verify_code参数,所以在callback时也不会提供code,这个库估计对此没有判断,只要callback时没有code就自动出错了。这种情况只能修改库代码了
mimzy
2015-03-17 09:09:34 +08:00
@raptor 好的!回头我再看下饭否的文档 感谢猛师傅指导~~(^0^*
mimzy
2015-11-19 02:32:39 +08:00
@raptor 时隔半年多我又重新研究了一遍,结果发现猛师傅说得完全正确啊!这个库通过判断 oauth_verifier 这个东西调用响应方法,但是饭否没传这个值,所以只好返回 None 了。我简单改了下库已经能用了,再次感谢猛师傅~
raptor
2015-11-19 09:58:38 +08:00
@mimzy 哈哈,解决就好
mimzy
2015-11-19 22:06:59 +08:00
最终解决反感:不修改 Flask-OAuthlib 这个库,而是在饭否的 Callback URL 末尾添加 ?oauth_verifier=0 ,这样传回来地址的时候 request.args 里就有了 oauth_verifier 这一项。 oauth_verifier 对于能否发消息无关紧要,但关系到 Flask-OAuthlib 判断应该调用 oauth1 还是 oauth2 的方法。
mimzy
2015-11-19 22:07:33 +08:00
反感 -> 方案

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/177145

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX