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

时间:2019-04-18 00:37:14

标签: python flask google-oauth flask-sqlalchemy flask-dance

对于我的Web应用程序,我正在使用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)

现在,我需要帮助修复数据库中的错误,但是如果您看到任何其他潜在的错误,将非常有帮助。在尝试自学这一过程时,我是Web开发的新手。由于此错误可以在代码中的任何位置产生,因此,我在下面附加了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)

0 个答案:

没有答案