Flask 2.3.2集成Flask-Security 3.0.0时before_first_request报错求助
问题:Flask-Security
roles_required装饰器触发AttributeError 错误详情
AttributeError: 'Flask' object has no attribute 'before_first_request'. Did you mean: '_got_first_request'?
当前Flask-Login的@login_required装饰器可正常使用,仅在使用Flask-Security的@roles_required时触发该错误。
相关代码文件
run.py
from app import create_app, db from config import Config from app.models import User app = create_app(Config) if __name__ == '__main__': app.run(debug=True)
models.py
import secrets from datetime import datetime from flask import current_app, request from flask_security import UserMixin, RoleMixin from itsdangerous import URLSafeTimedSerializer from app import db # Define association table for many-to-many relationship roles_users = db.Table('roles_users', db.metadata, db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), db.Column('role_id', db.Integer(), db.ForeignKey('role.id')) ) class Role(db.Model, RoleMixin): id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(80), unique=True) description = db.Column(db.String(255)) class User(UserMixin, db.Model): __tablename__ = 'WEB_Users' id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(120), unique=True, nullable=False) first_name = db.Column(db.String(50), nullable=False) last_name = db.Column(db.String(50), nullable=False) is_active = db.Column(db.Boolean, default=True) roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic'))
app/init.py
from flask import Flask, session from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_login import LoginManager # Flask-Login-Manager login_manager = LoginManager() login_manager.login_view = 'auth.login' # Flask-App-Factory db = SQLAlchemy() migrate = Migrate() def create_app(config_class): app = Flask(__name__) app.config.from_object(config_class) # Initialize extensions db.init_app(app) migrate.init_app(app, db) login_manager.init_app(app) # User loader for Flask-Login from app.models import User, Role @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) # Extend session validity @app.before_request def extend_session(): session.permanent = True # Register blueprints from app.auth.routes import auth_bp from app.dashboard.routes import dashboard_bp app.register_blueprint(auth_bp) app.register_blueprint(dashboard_bp) # Setup Flask-Security from flask_security import Security, SQLAlchemyUserDatastore user_datastore = SQLAlchemyUserDatastore(db, User, Role) security = Security(app, user_datastore) return app
routes.py
from flask import Blueprint, render_template from flask_login import login_required from flask_security import current_user, roles_accepted, roles_required test = Blueprint('test', __name__) @test.route('/admin') @login_required @roles_required('Admin') def admin(): print(current_user.roles) return "Admin"
解决方案
这个错误的核心原因是Flask 2.3+版本移除了before_first_request方法,而当前使用的Flask-Security版本仍在调用该方法。以下是两种解决途径:
1. 升级Flask-Security到兼容版本
旧版Flask-Security已停止维护,建议切换到官方维护的分支Flask-Security-Too,并确保版本>=5.3.0(该版本已适配Flask 2.3+的变化):
pip install --upgrade flask-security-too
2. 适配应用工厂模式的初始化方式(临时措施)
如果暂时无法升级,可修改app/__init__.py中Flask-Security的初始化代码,改用init_app方法适配应用工厂模式:
# 替换原有的Security初始化代码 from flask_security import Security, SQLAlchemyUserDatastore user_datastore = SQLAlchemyUserDatastore(db, User, Role) security = Security() # 先不传入app security.init_app(app, user_datastore) # 单独调用init_app
额外注意事项
检查models.py中的关联表外键定义:由于User模型设置了__tablename__ = 'WEB_Users',关联表roles_users中的外键应指向WEB_Users.id而非user.id,否则会导致数据库关联错误,修正如下:
roles_users = db.Table('roles_users', db.metadata, db.Column('user_id', db.Integer(), db.ForeignKey('WEB_Users.id')), # 修正此处 db.Column('role_id', db.Integer(), db.ForeignKey('role.id')) )
内容的提问来源于stack exchange,提问作者Shark00n
相关产品推荐
相关产品推荐

