对于我的网络应用程序,我使用 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)