我用 Flask、Flask-login 和 FLask-sqlalchemy 建立了一个带有用户登录的小网站。
生产时:
需要注意的是,我对两个不同的服务器有相同的行为:pythonanywhere 和 O2switch。所以,问题应该在我这边:/(或者两台服务器的配置错误?)
在本地,我没有问题(很难在其他设备上达到与生产环境相同的条件,但假设我作为第二个用户使用浏览器的隐身模式时没有问题)。
我正在使用的代码:
__init__.py
# library
from flask import Flask
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
# modules
from mywebsite_flask.config import config_selection
# init extensions
db = SQLAlchemy()
login_manager = LoginManager()
# app set-up
def create_app(config_mode):
app = Flask(__name__)
app.config.from_object(config_selection[config_mode])
# flask-login init
login_manager.login_view = "auth_bp.login"
login_manager.init_app(app)
# database init
db.init_app(app)
from mywebsite_flask.auth.models import Customer
with app.app_context():
db.create_all()
# add blueprints
from mywebsite_flask.public.routes import public_bp
app.register_blueprint(public_bp)
from mywebsite_flask.auth.routes import auth_bp
app.register_blueprint(auth_bp)
app.app_context().push()
return app
models.py
# library
from flask_login import UserMixin
# modules
from mywebsite_flask import db, login_manager
class Customer(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
email = db.Column(db.String, unique=True)
password = db.Column(db.String)
token_verification = db.Column(db.Boolean, default=False)
def __repr__(self):
return f"Customer #{self.id}:{self.email}>"
@login_manager.user_loader
def load_user(customer_id): # customer found by unique id
return Customer.query.get(int(customer_id))
auth.routes.py
# library
from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required, login_user, logout_user
from werkzeug.security import generate_password_hash
# modules
from mywebsite_flask import db
from mywebsite_flask.auth.models import Customer
# init
auth_bp = Blueprint("auth_bp", __name__)
@auth_bp.route("/login", methods=("GET", "POST"))
def login():
if not current_user.is_authenticated:
if request.method == "POST":
email = request.form.get("email").lower()
password = request.form.get("password")
remember = True if request.form.get("remember") else False
check_user = db.session.execute(
db.select(Customer).filter_by(email=email)
).scalar_one_or_none()
if not various_check(check_user):
# check that none of them are None
error_msg = "Un des champs requis est vide."
flash(error_msg, category="error")
else:
login_user(check_user, remember=remember)
return redirect(url_for("public_bp.home"))
return render_template("auth/login.html")
else:
return redirect(url_for("core_bp.customer_home"))
@auth_bp.route("/logout", methods=("GET", "POST"))
@login_required
def logout():
logout_user()
return redirect(url_for("public_bp.home"))
# end
我已经多次检查了我的代码,查看了 Flask-login 文档并阅读了一些类似的 stackoverflow 帖子,但无法找到解决方案。有人可能已经遇到这个问题或发现我的代码有问题吗?
编辑
请注意,当问题触发时:如果用户 B 在用户 A 登录后连接,我们会看到用户 A 的会话,但用户 B 端没有 cookie(但我们仍然可以看到并使用用户 A 会话) .
好的,我已经找到问题了。
在
init.py 的应用程序工厂
create_app()
中,我有 app.app_context().push()
我忘记了我不久前将其添加为快捷方式。这是为了轻松访问应用程序中各处的 app.config 参数。
问题已解决:
app.app_context().push()
current_app
(如果可能)或with app.app_context()
(如果没有),访问app.config(我原来的需要)app.app_context().push()
以某种方式干扰服务器上创建的不同会话(更具体地说,是来自 Flask 登录的 current_user
)
(感谢@relent95的帮助)