【问题标题】:Getting 'Missing required parameter: refresh_token' using Flask-dance with Google oauth使用 Flask-dance 和 Google oauth 获取“缺少所需参数:refresh_token”
【发布时间】:2019-12-16 20:33:50
【问题描述】:

我正在使用 Flask-dance 来对我的应用程序的用户进行身份验证。身份验证提供者是 Google。

有时会引发以下异常:

2019-08-09 08:07:26 default[20190809t105407]  "GET / HTTP/1.1" 500
2019-08-09 08:07:26 default[20190809t105407]  -- 0 --
2019-08-09 08:07:26 default[20190809t105407]  -- 1 --
2019-08-09 08:07:27 default[20190809t105407]  InvalidClientIdError was caught: (invalid_request) Missing required parameter: refresh_token

环顾这个问题,我可以找到两个方向:

  1. 在创建 Google 蓝图时使用 offline=True
  2. TokenExpiredError 实现错误处理程序

我两者都做了,并将我的应用程序部署到 GAE,但我仍然面临同样的错误。从堆栈跟踪中,我了解到正在调用错误处理程序,但是在代码尝试恢复时引发了“refresh_token”

我的代码:(代码基于Google QuickStart和Flask-dance问题143

import oauthlib
from flask import Flask, redirect, url_for, flash, session, current_app
from flask_dance.contrib.google import make_google_blueprint, google
import os
import time
from oauthlib.oauth2.rfc6749.errors import InvalidClientIdError, TokenExpiredError

GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID", None)
GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET", None)

app = Flask(__name__)
app.secret_key = "TODO_TODO"
blueprint = make_google_blueprint(
    client_id=GOOGLE_CLIENT_ID,
    client_secret=GOOGLE_CLIENT_SECRET,
    offline=True
)
app.register_blueprint(blueprint, url_prefix="/login")


@app.route('/logout', methods=['GET'])
def logout():
    _revoke_token_and_empty_session()
    return redirect(url_for('app.index'))


def _revoke_token_and_empty_session():
    print('inside _revoke_token_and_empty_session')
    if google.authorized:
        try:
            google.get(
                'https://accounts.google.com/o/oauth2/revoke',
                params={
                    'token':
                        current_app.blueprints['google'].token['access_token']},
            )
        except TokenExpiredError:
            pass
        except InvalidClientIdError:
            # Our OAuth session apparently expired. We could renew the token
            # and logout again but that seems a bit silly, so for now fake
            # it.
            pass
    session.clear()


@app.errorhandler(oauthlib.oauth2.rfc6749.errors.TokenExpiredError)
def token_expired(_):
    print('In TokenExpiredError')
    del blueprint.token
    _revoke_token_and_empty_session()
    flash('Your session had expired. Please submit the request again',
          'error')
    return redirect(url_for('app.index'))


@app.route("/")
def index():
    print('-- 0 --')
    if not google.authorized:
        return redirect(url_for("google.login"))
    print('-- 1 --')
    user_info_url = 'https://openidconnect.googleapis.com/v1/userinfo'
    try:
        resp = google.get(user_info_url)
    except InvalidClientIdError as e:
        #
        # Here is the problem
        #
        print('InvalidClientIdError was caught: {}'.format(str(e)))
        return 'Having an InvalidClientIdError issue: {}'.format(str(e)), 500
    else:
        print('-- 2 --')
        user_info = resp.json()
        return "You are {user_name} on Google. Time: {t}".format(user_name=user_info['name'], t=time.time())


if __name__ == "__main__":
    app.run()

我目前的理解是TokenExpiredError 被捕获并调用了函数index。当函数尝试调用resp = google.get(user_info_url) 时,会引发InvalidClientIdError: (invalid_request) Missing required parameter: refresh_token

知道怎么解决吗?

【问题讨论】:

  • 在运行del blueprint.token 之前,打印出该变量的内容。它应该是一本字典——该字典中有refresh_token 键吗?如果没有,那么 Google 没有给你一个刷新令牌,所以 Flask-Dance 不能发送它。

标签: python google-app-engine flask oauth flask-dance


【解决方案1】:

从您的代码和烧瓶代码来看,您似乎正在尝试在撤销之前删除令牌,即使它已经无效。如果您想避免传递“offline=True”,请尝试简化代码,因为不需要刷新任何内容(用户将被重定向),并且令牌已经无效,因此撤销没有多大意义它要么。我也只设置了一个错误处理程序。

这是对我有用的代码:

import oauthlib
from flask import Flask, redirect, url_for, flash, session, current_app
from flask_dance.contrib.google import make_google_blueprint, google
import os
import time
from oauthlib.oauth2.rfc6749.errors import InvalidClientIdError, TokenExpiredError

GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID", None)
GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET", None)

app = Flask(__name__)
app.secret_key = "TODO_TODO"
blueprint = make_google_blueprint(
    client_id=GOOGLE_CLIENT_ID,
    client_secret=GOOGLE_CLIENT_SECRET,
    offline=True
)
app.register_blueprint(blueprint, url_prefix="/login")


@app.route('/logout', methods=['GET'])
def logout():
    """
    This endpoint tries to revoke the token
    and then it clears the session
    """
    if google.authorized:
        try:
            google.get(
                'https://accounts.google.com/o/oauth2/revoke',
                params={
                    'token':
                        current_app.blueprints['google'].token['access_token']},
            )
        except TokenExpiredError:
            pass
        except InvalidClientIdError:
            # Our OAuth session apparently expired. We could renew the token
            # and logout again but that seems a bit silly, so for now fake
            # it.
            pass
    _empty_session()
    return redirect(url_for('app.index'))


def _empty_session():
    """
    Deletes the google token and clears the session
    """
    if 'google' in current_app.blueprints and hasattr(current_app.blueprints['google'], 'token'):
        del current_app.blueprints['google'].token
    session.clear()


@app.errorhandler(oauthlib.oauth2.rfc6749.errors.TokenExpiredError)
@app.errorhandler(oauthlib.oauth2.rfc6749.errors.InvalidClientIdError)
def token_expired(_):
    _empty_session()
    return redirect(url_for('app.index'))

@app.route("/")
def index():
    print('-- 0 --')
    if not google.authorized:
        return redirect(url_for("google.login"))
    print('-- 1 --')
    user_info_url = 'https://openidconnect.googleapis.com/v1/userinfo'
    resp = google.get(user_info_url)
    user_info = resp.json()
    return "You are {user_name} on Google. Time: {t}".format(user_name=user_info['name'], t=time.time())


if __name__ == "__main__":
    app.run()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-31
    • 2021-10-23
    • 2013-01-10
    • 2016-12-14
    • 2015-07-13
    • 2012-01-02
    • 2022-12-10
    • 1970-01-01
    相关资源
    最近更新 更多