Как исправить ошибку SQLAlchemy IntegrityError при попытке исправить ошибку «Невозможно получить токен OAuth без связанного пользователя» в Flask-Dance - PullRequest
1 голос
/ 18 апреля 2019

В своем веб-приложении я использую Flask-Dance, чтобы пользователи создавали свои учетные записи, входя только в свои учетные записи Google (я не хочу, чтобы им приходилось вводить какие-либо новые имена пользователей или пароли). Когда я впервые попытался сделать это, я столкнулся с ошибкой:

Cannot get OAuth token without an associated user

Я нашел другой пост, посвященный этой проблеме (Ссылка на него: flask_dance: Невозможно получить токен OAuth без ассоциированного пользователя ). Часть ответа № 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)
...