V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mimzy
V2EX  ›  Flask

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

  •  1
     
  •   mimzy ·
    mookrs · 2015-03-16 00:45:35 +08:00 · 4114 次点击
    这是一个创建于 3326 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    8 条回复    2015-11-19 22:07:33 +08:00
    raptor
        1
    raptor  
       2015-03-16 14:17:25 +08:00   ❤️ 1
    不知道flask_oauthlib是怎么实现的,我用reqeusts自己做过一个实现是没问题的: https://bitbucket.org/raptorz/restclient。

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

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

    关于 Callback URL,用这个库时只要我填上就能跳转回来,不填的话就直接留在授权成功页面了。这个我也再研究研究。
    raptor
        3
    raptor  
       2015-03-17 08:56:44 +08:00   ❤️ 1
    @mimzy 那我大概知道了。因为饭否在响应时默认不使用code项,即在调用access_token时不需要传入verify_code参数,所以在callback时也不会提供code,这个库估计对此没有判断,只要callback时没有code就自动出错了。这种情况只能修改库代码了
    mimzy
        4
    mimzy  
    OP
       2015-03-17 09:09:34 +08:00
    @raptor 好的!回头我再看下饭否的文档 感谢猛师傅指导~~(^0^*
    mimzy
        5
    mimzy  
    OP
       2015-11-19 02:32:39 +08:00
    @raptor 时隔半年多我又重新研究了一遍,结果发现猛师傅说得完全正确啊!这个库通过判断 oauth_verifier 这个东西调用响应方法,但是饭否没传这个值,所以只好返回 None 了。我简单改了下库已经能用了,再次感谢猛师傅~
    raptor
        6
    raptor  
       2015-11-19 09:58:38 +08:00   ❤️ 1
    @mimzy 哈哈,解决就好
    mimzy
        7
    mimzy  
    OP
       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
        8
    mimzy  
    OP
       2015-11-19 22:07:33 +08:00
    反感 -> 方案
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3635 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 44ms · UTC 10:48 · PVG 18:48 · LAX 03:48 · JFK 06:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.