Flask-login未调用load_user,用户认证状态无法跨请求持久化
问题描述
向/api/login发送POST请求登录后,从未返回“用户已登录”提示;访问/api/user也无法返回已认证用户的邮箱。在load_user函数中添加打印语句后,该函数从未被调用。用户创建并提交到数据库后能成功生成ID,注册、数据库持久化、登录流程本身正常,但用户认证状态无法在请求间保持。
相关代码
init.py
# standard library imports # third-party imports from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_cors import CORS from flask_login import LoginManager # local from site_t.config import Config app = Flask(__name__) app.config.from_object(Config) db = SQLAlchemy(app) CORS(app, supports_credentials=True) login = LoginManager(app) login.session_protection = "strong" @app.before_first_request def create_tables(): db.create_all() from site_t import routes, models
models.py
from flask_login import UserMixin from werkzeug.security import generate_password_hash, check_password_hash from site_t import db, login @login.user_loader def load_user(id): return User.query.get(int(id)) class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) def __repr__(self): return '<User {}>'.format(self.email) def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password)
Routes.py
# third party imports from flask import request, jsonify from flask_login import login_user, current_user, login_required # local imports from site_t import app, db from site_t.models import User from site_t.communication.receiver import parse_login_request, parse_registration_request # NOTE: This route is needed for the default EB health check route @app.route('/') def home(): return jsonify({'message': 'Welcome to the API'}) @app.route("/api/login", methods=["POST"]) # type: ignore def login(): if current_user.is_authenticated: return jsonify({"message": "User already logged in"}), 200 try: email, password = parse_login_request(request) except ValueError as e: return jsonify({"message": str(e)}), 400 user = User.query.filter_by(email=email).first() if user is None or not user.check_password(password): return jsonify({"message": "Invalid email or password"}), 200 login_user(user, remember=True) return jsonify({"message": "Login successful"}), 200 def create_user(email, password): user = User(email=email) user.set_password(password) return user @app.route("/api/register", methods=["GET", "POST"]) # type: ignore def register(): if current_user.is_authenticated: return jsonify({"message": "User already logged in"}), 400 try: email, password = parse_registration_request(request) except ValueError as e: return jsonify({"message": str(e)}), 400 if User.query.filter_by(email=email).first() is not None: return jsonify({"message": "Email already registered"}), 200 user = create_user(email, password) db.session.add(user) db.session.commit() return jsonify({"message": "Registration successful"}), 200 @app.route("/api/user", methods=["GET, POST"]) # type: ignore @login_required def get_user(): if not current_user.is_authenticated: return jsonify({"message": "User not logged in"}), 400 return jsonify({"email": current_user.email})
wsgi.py
from site_t import app if __name__ == '__main__': app.run()
问题排查与修复方案
1. 缺失会话密钥配置
Flask-Login依赖Flask的会话机制存储用户认证状态,必须配置SECRET_KEY才能正常加密会话数据,否则会话无法在请求间持久化。
- 修复方法:在
Config类中添加SECRET_KEY,生产环境使用随机生成的安全密钥:# config.py import os class Config: SECRET_KEY = os.urandom(24) # 生产环境用随机生成的密钥 # 其他已有配置...
2. 路由请求方法配置错误
/api/user路由的methods参数写法错误,"GET, POST"是单个字符串,Flask无法识别正确的请求方法,导致login_required装饰器无法触发会话校验。
- 修复方法:修改为正确的列表格式:
@app.route("/api/user", methods=["GET", "POST"]) # 逗号分隔每个方法,各自用引号包裹 @login_required def get_user(): # 原代码逻辑不变
3. 跨域请求凭证携带问题
即使后端设置了CORS(app, supports_credentials=True),前端请求时也必须显式携带凭证(Cookie),否则会话无法在跨域请求间保持。
- 前端修复示例:
- Axios:
axios.get('/api/user', { withCredentials: true }) - Fetch:
fetch('/api/user', { credentials: 'include' })
- Axios:
4. 会话Cookie安全配置(生产环境必备)
部署到生产环境时,需配置合适的Cookie属性避免会话劫持:
# 在Config类中添加 SESSION_COOKIE_SECURE = True # 仅HTTPS下传输Cookie SESSION_COOKIE_HTTPONLY = True # 禁止JS访问Cookie,防止XSS攻击 SESSION_COOKIE_SAMESITE = "Lax" # 限制跨站Cookie发送,根据跨域需求调整为"Strict"或"None"
5. 验证load_user注册顺序
确保login对象初始化完成后再导入models模块(因为models中的@login.user_loader需要绑定到已初始化的login实例),当前init.py的导入顺序是正确的(先初始化login,再导入routes和models),若存在循环导入问题,可调整导入位置。
验证步骤
- 启动服务后,先注册用户,确认数据库中生成用户记录。
- 发送登录请求,确保返回
Login successful。 - 携带凭证访问
/api/user,检查是否返回用户邮箱。 - 查看
load_user函数的打印输出,确认该函数被调用。
内容的提问来源于stack exchange,提问作者aloha_erich
相关产品推荐
相关产品推荐

