swo*_*ish 4 flask flask-sqlalchemy
我想用我的应用程序迁移flask_dance,以便用户使用谷歌和其他社交网络进行授权.
我收到此错误:
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
Run Code Online (Sandbox Code Playgroud)
这也是我的表格如何在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)
Run Code Online (Sandbox Code Playgroud)
请任何帮助将不胜感激:)
sin*_*boy 10
TL; DR:您可以通过设置禁用此异常user_required=False的上SQLAlchemyBackend对象.但是,由于某种原因引发异常,如果您只是像这样禁用它,您的数据库可能会进入意外状态,其中某些OAuth令牌未链接到用户.有一种更好的方法可以解决这个问题.继续阅读以了解详情.
我是Flask-Dance的作者.此Cannot get OAuth token without an associated user异常仅出现在Flask-Dance的0.13.0及更高版本中.(CHANGELOG就在这里.)引入此更改的pull请求有更多关于更改原因的上下文.
有几种不同的方法可以使用OAuth.以下是一些示例用例,所有这些都是Flask-Dance支持的:
用例1是最简单的:不要传递user或user_id参数SQLAlchemyStorage,并假设您的应用程序不使用多个用户帐户.这意味着您的网站只能链接到远程服务上的一个特定帐户:只有一个Twitter帐户,只有一个Slack团队等.
用例2也很简单:将一个user或user_id参数传递给你的SQLAlchemyStorage.Flask-Dance会自动将OAuth令牌保存到您的数据库中,并将其链接到当前登录的用户.
用例3更复杂,因为它涉及同时自动创建OAuth令牌和本地用户帐户.不同的应用程序对创建用户帐户有不同的要求,Flask-Dance无法知道这些要求是什么.因此,Flask-Dance无法自动处理此用例.您必须挂钩oauth_authorized信号,创建用户帐户并手动将其与OAuth令牌关联,然后返回False告诉Flask-Dance不要尝试自动处理OAuth令牌.
在版本0.13.0之前,可能会在数据库中意外创建未与任何用户链接的OAuth令牌.在用例3中,OAuth令牌是在该用户的本地用户帐户存在之前创建的,因此Flask-Dance会将OAuth令牌保存到数据库而不使用任何链接的本地用户帐户.您可以使用oauth_authorized处理程序与本地用户帐户OAuth令牌关联之后,但如果你的代码是越野车,并抛出一个异常,那么OAuth令牌可以留在你的数据库中,永远未链接到任何用户.
从版本0.13.0开始,Flask-Dance检测到此问题并引发异常,而不是在没有关联的本地用户帐户的情况下将OAuth令牌保存到数据库.有两种方法可以解决此问题:
user_required=False的上SQLAlchemyStorage对象.我相信选项1是目前为止更好的解决方案,但它需要更多地了解Flask-Dance在幕后实际做的事情.我写了一些文档来描述如何处理多用户设置,这也讨论了这个问题.
| 归档时间: |
|
| 查看次数: |
901 次 |
| 最近记录: |