我想使用我的应用程序迁移flask_dance,以使用户授权使用Google和其他社交网络。
我收到此错误:Cannot get OAuth token without an associated user
在我完成蓝图和sqlalchemy后端之间的连接之前,该应用程序运行正常,如果我删除了google_blueprint.backend
行,该错误将消失。
这是我的 __init__.py :
import os
from flask import Flask, redirect, url_for, current_app
from flask_login import current_user
from develop.models import (
db,
User,
OAuth
)
from flask_dance.contrib.google import make_google_blueprint
from flask_dance.consumer.backend.sqla import SQLAlchemyBackend
from flask_dance.consumer import oauth_authorized
from sqlalchemy.orm.exc import NoResultFound
def create_app(config_object):
app = Flask(__name__)
app.config.from_object(config_object)
db.init_app(app)
login_manager.init_app(app)
google_blueprint = make_google_blueprint(
client_id=app.config['GOOGLE_CLIENT_ID'],
client_secret=app.config['GOOGLE_CLIENT_SECRET'],
scope=["profile", "email"]
)
app.register_blueprint(google_blueprint, url_prefix='/login')
@oauth_authorized.connect_via(google_blueprint)
def google_logged_in(blueprint, token):
resp = blueprint.session.get("/oauth2/v2/userinfo")
if resp.ok:
account_info_json = resp.json()
email = account_info_json['email']
query = User.query.filter_by(email=email)
try:
user = query.one()
except NoResultFound:
user = User()
user.image = account_info_json['picture']
user.fullname = account_info_json['name']
user.username = account_info_json['given_name']
user.email = account_info_json['email']
db.session.add(user)
db.session.commit()
login_user(get_user, remember=True)
identity_changed.send(
current_app._get_current_object(),
identity=Identity(get_user.id)
)
@login_manager.user_loader
def load_user(userid):
return User.query.get(userid)
google_blueprint.backend = SQLAlchemyBackend(OAuth, db.session, user=current_user)
return app
这也是我在 models.py 中如何组织它们的表格:
class User(db.Model, UserMixin):
id = db.Column(db.Integer(), primary_key=True)
image = db.Column(db.String(), nullable=True)
fullname = db.Column(db.String())
username = db.Column(db.String(), unique=True)
password = db.Column(db.String())
email = db.Column(db.String(), unique=True)
class OAuth(OAuthConsumerMixin, db.Model):
user_id = db.Column(db.Integer(), db.ForeignKey(User.id))
user = db.relationship(User)
请任何帮助将不胜感激:)
最佳答案
TL; DR:您可以通过在SQLAlchemyStorage对象上设置user_required=False
来禁用此异常。但是,引发异常是有原因的,如果您仅以此方式禁用它,则数据库可能会进入意外状态,其中某些OAuth token 未链接到用户。有一种更好的方法可以解决此问题。继续阅读以获取详细信息。
我是Flask-Dance的作者。仅在Flask-Dance的0.13.0及更高版本中存在此Cannot get OAuth token without an associated user
异常。 (CHANGELOG is here.)pull request introducing this change具有更多有关更改原因的上下文。
有几种使用OAuth的方法。以下是一些示例用例,Flask-Dance支持所有这些用例:
用例1最简单:不要将
user
或user_id
参数传递给SQLAlchemyStorage
,并且将假定您的应用程序不使用多个用户帐户。这意味着您的网站只能链接到远程服务上的一个特定帐户:只有一个Twitter帐户,只有一个Slack团队等。用例2也非常简单:将
user
或user_id
参数传递给SQLAlchemyStorage
。 Flask-Dance会自动将OAuth token 保存到您的数据库中,并将其链接到当前登录的用户。用例3更复杂,因为它涉及同时自动创建OAuth token 和本地用户帐户。不同的应用程序对创建用户帐户有不同的要求,而Flask-Dance无法知道这些要求是什么。结果,Flask-Dance无法自动处理此用例。您必须挂接到
oauth_authorized
信号,创建用户帐户并将其手动与OAuth token 相关联,然后返回False
告诉Flask-Dance不要尝试自动处理OAuth token 。在版本0.13.0之前,可能会在数据库中意外创建根本未与任何用户链接的OAuth token 。在用例3中,在为该用户创建本地用户帐户之前创建了OAuth token ,因此Flask-Dance会将OAuth token 保存到数据库中,而无需任何链接的本地用户帐户。之后,您可以使用
oauth_authorized
处理程序将OAuth token 与本地用户帐户相关联,但是如果您的代码有错误并引发异常,则OAuth token 可能会保留在您的数据库中,永远不会与任何用户链接。从0.13.0版开始,Flask-Dance会检测到此问题并引发异常,而不是在没有关联的本地用户帐户的情况下将OAuth token 保存到数据库中。有两种方法可以解决此问题:
user_required=False
对象上设置SQLAlchemyStorage
来禁用此检查。 我相信到目前为止,选择1是更好的解决方案,但是它需要对Flask-Dance在幕后的实际操作有更多的了解。 I've written some documentation that describes how to handle multi-user setups, which discusses this problem as well.
关于flask - flask_dance : Cannot get OAuth token without an associated user,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47643448/