首页 > 解决方案 > 如何在尝试修复 Flask-Dance 中的“无法在没有关联用户的情况下获取 OAuth 令牌”错误时修复 SQLAlchemy IntegrityError

问题描述

对于我的网络应用程序,我使用 Flask-Dance 让用户只通过登录他们的 Google 帐户来创建他们的帐户(我不希望他们必须创建任何新的用户名或密码)。当我第一次尝试这样做时,我遇到了错误:

Cannot get OAuth token without an associated user

我发现了另一个处理这个问题的帖子(链接到它:flask_dance: Cannot get OAuth token without an associated user)。答案的#3 部分是我正在尝试做的事情,但是当我尝试“手动创建用户帐户并将其与 OAuth 令牌相关联”时,我从 SQLAlchemy 收到以下错误:

sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) datatype mismatch

我几乎可以肯定这是来自令牌。我不知道为什么它不接受我传递给它的令牌。如果我能够解决此错误,我认为代码将手动创建用户帐户并将其与 OAuth 令牌相关联,然后我可以摆脱(正如其他帖子所说的那样):

行中的“user_required=False”:

google_blueprint.backend = SQLAlchemyBackend(OAuth, db.session, user=current_user, user_required=False)

现在我需要帮助修复数据库错误,但如果您发现任何其他潜在错误,这将非常有帮助。我是网络开发的新手,因为我正在尝试自学这个过程。由于此错误可能源于我的代码中的任何位置,因此我在下面附上了我的 python 文件。

import os
import json
import datetime
from flask import Flask, redirect, url_for
from flask_dance.contrib.google import make_google_blueprint, google
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin, current_user, LoginManager, login_required, login_user, logout_user
from flask_dance.consumer.backend.sqla import OAuthConsumerMixin, SQLAlchemyBackend
from flask_dance.consumer import oauth_authorized
from sqlalchemy.orm.exc import NoResultFound

app = Flask(__name__)
app.config['SECRET_KEY'] = 'thisissupposedtobeasecret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////Users/kentjo/Documents/git/CareerDay/login.db'

os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = '1'
os.environ["OAUTHLIB_RELAX_TOKEN_SCOPE"] = '1'

google_blueprint = make_google_blueprint(
    client_id='#removed for security of this post#', 
    client_secret='#removed for security of this post#',
    scope=['profile', 'email'],
    offline=True   #added in 
)

app.register_blueprint(google_blueprint, url_prefix='/google_login')

db = SQLAlchemy(app)
login_manager = LoginManager(app)

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(250), unique=True)
    first_name = db.Column(db.String(250), unique=False)
    last_name = db.Column(db.String(250), unique=False)
    time_stamp = db.Column(db.String(25), unique=False)
    first_choice = db.Column(db.String(250), unique=False)
    second_choice = db.Column(db.String(250), unique=False)
    third_choice = db.Column(db.String(250), unique=False)
    fourth_choice = db.Column(db.String(250), unique=False)
    fifth_choice = db.Column(db.String(250), unique=False)
    submitted = db.Column(db.Boolean, unique=False, default=True)

class OAuth(OAuthConsumerMixin, db.Model):
    user_id = db.Column(db.Integer, db.ForeignKey(User.id))
    user = db.relationship(User)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

google_blueprint.backend = SQLAlchemyBackend(OAuth, db.session, user=current_user, user_required=False) #Eventually need to remove user_required=False

@app.route('/google')
def google_login():

    if not google.authorized:
        return redirect(url_for('google.login'))

    account_info = google.get('/plus/v1/people/me')

    account_info_json = account_info.json()
    json_str = json.dumps(account_info_json)

    email = json.loads(json.dumps(json.loads(json_str)['emails']))[0]['value']

    return '<h1>Your email is {}'.format(email)


@oauth_authorized.connect_via(google_blueprint)
def google_logged_in(blueprint, token):

    account_info = blueprint.session.get('/plus/v1/people/me') 

    if account_info.ok:
        account_info_json = account_info.json()

        json_str = json.dumps(account_info_json)

        google_email=json.loads(json.dumps(json.loads(json_str)['emails']))[0]['value']
        google_first_name=json.loads(json.dumps(json.loads(json_str)['name']))['givenName']
        google_last_name=json.loads(json.dumps(json.loads(json_str)['name']))['familyName']

        google_id=json.loads(json.dumps(json.loads(json_str)['id']))

        query = User.query.filter_by(email=google_email)

        try:
            user = query.one()
            print("FOUND USER")
        except NoResultFound:
            print("NO USER FOUND: proceed to create")
            user = User(
                email=google_email,
                first_name=google_first_name,
                last_name=google_last_name
            )
            oauth = OAuth(
                id=google_id,
                provider=blueprint.name,
                created_at=datetime.datetime.now(),
                token=token,  #PROBLEM COMING FROM HERE
                user_id=user.id
            )
            oauth.user = user
            db.session.add(user)
            db.session.add(oauth)
            db.session.commit()

        login_user(user)

        return False

@app.route('/')
@login_required
def index():
    return '<h1>You are logged in as {}'.format(current_user.email)

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('index'))

if __name__ == '__main__':
    app.run(debug=True)

标签: pythonflaskgoogle-oauthflask-sqlalchemyflask-dance

解决方案


推荐阅读