Flask случайным образом возвращает пользователя как не вошедшего в систему, когда он

У меня есть проект Flask разумного размера, который отлично работает при локальном запуске, однако при запуске через сервер Apache или Nginx (локально или внешне) пользователям иногда будет предлагаться, что они не вошли в систему, прежде чем их несколько раз перенаправят.

Ниже приведен журнал, показывающий, что пользователь был перенаправлен с / на /login 9 раз, прежде чем войти в систему.

[10:57:35] "GET /user/1 HTTP/1.1" 200 12277 "redacted/fleet" 7.36"
[10:57:36] "GET /user/1 HTTP/1.1" 302 770 "redacted/user/1" 7.36"
[10:57:36] "GET /login?next=%2Fuser%2F1 HTTP/1.1" 302 736 "redacted/user/1" 7.36"
[10:57:36] "GET / HTTP/1.1" 302 787 "redacted/user/1" 7.36"
[10:57:36] "GET /login?next=%2F HTTP/1.1" 302 745 "redacted/user/1" 7.36"
[10:57:36] "GET / HTTP/1.1" 302 789 "redacted/user/1" 7.36"
[10:57:36] "GET /login?next=%2F HTTP/1.1" 302 747 "redacted/user/1" 7.36"
[10:57:36] "GET / HTTP/1.1" 302 789 "redacted/user/1" 7.36"
[10:57:36] "GET /login?next=%2F HTTP/1.1" 302 749 "redacted/user/1" 7.36"
[10:57:36] "GET / HTTP/1.1" 302 793 "redacted/user/1" 7.36"
[10:57:36] "GET /login?next=%2F HTTP/1.1" 302 751 "redacted/user/1" 7.36"
[10:57:36] "GET / HTTP/1.1" 302 793 "redacted/user/1" 7.36"
[10:57:36] "GET /login?next=%2F HTTP/1.1" 302 751 "redacted/user/1" 7.36"
[10:57:36] "GET / HTTP/1.1" 302 794 "redacted/user/1" 7.36"
[10:57:36] "GET /login?next=%2F HTTP/1.1" 302 752 "redacted/user/1" 7.36"
[10:57:36] "GET / HTTP/1.1" 302 795 "redacted/user/1" 7.36"
[10:57:36] "GET /login?next=%2F HTTP/1.1" 302 753 "redacted/user/1" 7.36"
[10:57:36] "GET / HTTP/1.1" 302 795 "redacted/user/1" 7.36"
[10:57:37] "GET /login?next=%2F HTTP/1.1" 302 752 "redacted/user/1" 7.36"
[10:57:37] "GET / HTTP/1.1" 302 797 "redacted/user/1" 7.36"
[10:57:37] "GET /login?next=%2F HTTP/1.1" 302 756 "redacted/user/1" 7.36"
[10:57:37] "GET /user/1 HTTP/1.1" 302 822 "redacted/user/1" 7.36"
[10:57:37] "GET /login?next=%2Fuser%2F1 HTTP/1.1" 302 756 "redacted/user/1" 7.36"
[10:57:37] "GET / HTTP/1.1" 200 4013 "redacted/user/1" 7.36"
[10:57:40] "GET /user/1 HTTP/1.1" 200 12273 "redacted/" 7.36"

Пользователю не нужно снова входить в систему, достаточно просто обновить страницу несколько раз, однако эта проблема продолжает возникать.

Моя функция user_loader выглядит следующим образом:

@login_manager.user_loader
def load_user(user_id):
    return db.session.get(User, int(user_id))

Поскольку я не могу достоверно воспроизвести проблему, я не могу привести пример.

Я использую;

  • Flask-SQLAlchemy 3.1.1
  • Колба 3.0.2
  • Flask-Вход 0.6.3
  • Колба-WTF 1.2.1
  • Версия Nginx: nginx/1.18.0 (Ubuntu)

База данных – mysql версии 8.0.35 с PhpMyAdmin, размещенным на том же компьютере.

Конфигурации Nginx;

server {
    listen 80;
    server_name [REDACTED URL];
        
    access_log      /var/log/nginx/access.[REDACTED URL].log;
    error_log       /var/log/nginx/error.[REDACTED URL].log;

    location / {
        proxy_pass http://unix:/home/gunicorn/run/[REDACTED URL].sock;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Prefix /;
    };
}

Конфигурация сервиса;

[Unit]
Description=Development
After=network.target

[Service]
User=gunicorn
Group=www-data
WorkingDirectory=/home/gunicorn/[REDACTED URL]/[REDACTED NAME]
Environment = "PATH=/home/gunicorn/[REDACTED URL]/[REDACTED NAME]/venv/bin"
ExecStart=/home/gunicorn/[REDACTED URL]/[REDACTED NAME]/venv/bin/gunicorn --workers 3 --bind unix:/home/gunicorn/run/[REDACTED URL].sock -m 007 wsgi:application

[Install]
WantedBy=multi-user.target

Пример кода приложения;

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = '[REDACTED]'
app.config['permanent_session_lifetime'] = timedelta(days=364)

app.wsgi_app = ProxyFix(
    app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)

login_manager = LoginManager(app)
login_manager.init_app(app)
login_manager.login_view = 'login'

mail = Mail(app)
db = SQLAlchemy(app)

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        flash('Already logged in!', 'danger')
        return redirect(url_for('home'))

    email_login_form = EmailLoginForm()
    if 'email_login_submit' in request.form:
        if email_login_form.validate_on_submit():
            account_check = User.query.filter_by(user_email=email_login_form.user_email.data).first()
            if account_check is None:
                flash('Incorrect email or password!', 'danger')
                return redirect(url_for('login'))

            if not account_check.check_password(email_login_form.user_password.data):
                flash('Incorrect email or password!', 'danger')
                return redirect(url_for('login'))

            login_user(account_check, remember=True)

            return redirect(url_for('home'))

    return render_template('login.html', email_login_form=email_login_form)
        
@app.route("/", methods=['GET', 'POST'])
@login_required
def home():
    return render_template('dashboard.html')
        
if __name__ == "__main__":
    app.run(host='0.0.0.0')

Все еще ищу помощь по этому поводу, пожалуйста!

Reuben 19.04.2024 17:49

Можно ли обновить этот вопрос, включив в него минимальный воспроизводимый пример , воспроизводящий поведение? Как вы запускаете свое приложение flask — через mod_wsgi, через прокси или какой-либо другой механизм? Пожалуйста, покажите нам конкретную конфигурацию.

larsks 19.04.2024 18:42

Я не уверен в остальной части вашего синтаксиса, но кое-что приходит на ум: убедиться, что вы используете правильный экземпляр «пользователя». Убедитесь, что вы используете класс во всем своем коде и нигде не создаете статическую переменную.

jcruzer 19.04.2024 21:36

@larsks Трудно воспроизвести проблему. При запуске локального сервера разработки проблем нет. Когда я развертываю тот же код и использую Apache или Ngnix, возникает случайная проблема. Сейчас использую Ngnix и Gunicorn. Какую конфигурацию вы хотели бы видеть?

Reuben 21.04.2024 18:52

Есть ли у вас какой-либо код, который обрабатывает отсутствие входа пользователя в систему? Пожалуйста, поделитесь тем же.

hehe 22.04.2024 21:36

@Рубен, не могли бы вы включить конфигурацию, которая у вас есть при развертывании, а также минимальный код входа в колбу?

LiteApplication 23.04.2024 21:52

@Reuben Пожалуйста, добавьте все, что можете, из следующего, что я упоминаю в вашем вопросе: используемую версию nginx/apache, любые используемые конфигурации и изменения, о которых стоит упомянуть, например. wsgi, код, который обрабатывает перенаправление от root к входу в систему (происходит 9 раз, так что, может быть, он вызывался неоднократно?) и, наконец, любой код, который, как вы подозреваете, является причиной.

AdityaDN 24.04.2024 16:54

Если это происходит во время POST-запроса возможно, в этом проблема

AdityaDN 24.04.2024 17:00

@hehe Не существует специального кода, который обрабатывал бы пользователя, не входящего в систему, просто используется реализация по умолчанию «@login_required».

Reuben 25.04.2024 16:54

@LiteApplication Я обновил исходное сообщение, указав конфигурацию и код входа.

Reuben 25.04.2024 16:55

@AdityaDN Я обновил исходный пост. К сожалению, это происходит как с запросами GET, так и с POST, спасибо за эту ссылку, хотя попробовать стоило.

Reuben 25.04.2024 16:56

@Рубен, кажется, с кодом все в порядке, можешь попробовать if request.method == "POST" отделить часть сообщения и удалить эти URL-адреса себе. Этот заблудший db.session.commit() появился по ошибке, верно? Наконец, попробуйте установить app.config['SECRET_KEY'] на что-нибудь постоянное. IDK, если ничего из этого, возможно, проблема в конфигурации сервера.

AdityaDN 25.04.2024 18:13

@AdityaDN Случайный коммит — ошибка, я обновлю исходный пост. Я также пробовал менять секретные ключи. Основная проблема в том, что это может быть сделано на любой странице, а не только при входе в систему. Кроме того, пользователь на самом деле не вышел из системы, просто кажется, что пользователь не аутентифицирован, но затем обновляется одна и та же страница 1 или 2 раза, а затем отображается, что пользователь прошел аутентификацию без необходимости повторного входа в систему.

Reuben 25.04.2024 18:36
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
13
122
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Удалось решить проблему. Оказывается, там остался некоторый код разработки;

with app.app_context():
    db.reflect()
    db.create_all()

Удаление решило все проблемы. Абсолютный кошмар, который нужно выследить.

Другие вопросы по теме