У меня есть проект 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))
Поскольку я не могу достоверно воспроизвести проблему, я не могу привести пример.
Я использую;
База данных – 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')
Можно ли обновить этот вопрос, включив в него минимальный воспроизводимый пример , воспроизводящий поведение? Как вы запускаете свое приложение flask — через mod_wsgi
, через прокси или какой-либо другой механизм? Пожалуйста, покажите нам конкретную конфигурацию.
Я не уверен в остальной части вашего синтаксиса, но кое-что приходит на ум: убедиться, что вы используете правильный экземпляр «пользователя». Убедитесь, что вы используете класс во всем своем коде и нигде не создаете статическую переменную.
@larsks Трудно воспроизвести проблему. При запуске локального сервера разработки проблем нет. Когда я развертываю тот же код и использую Apache или Ngnix, возникает случайная проблема. Сейчас использую Ngnix и Gunicorn. Какую конфигурацию вы хотели бы видеть?
Есть ли у вас какой-либо код, который обрабатывает отсутствие входа пользователя в систему? Пожалуйста, поделитесь тем же.
@Рубен, не могли бы вы включить конфигурацию, которая у вас есть при развертывании, а также минимальный код входа в колбу?
@Reuben Пожалуйста, добавьте все, что можете, из следующего, что я упоминаю в вашем вопросе: используемую версию nginx/apache, любые используемые конфигурации и изменения, о которых стоит упомянуть, например. wsgi, код, который обрабатывает перенаправление от root к входу в систему (происходит 9 раз, так что, может быть, он вызывался неоднократно?) и, наконец, любой код, который, как вы подозреваете, является причиной.
Если это происходит во время POST-запроса возможно, в этом проблема
@hehe Не существует специального кода, который обрабатывал бы пользователя, не входящего в систему, просто используется реализация по умолчанию «@login_required».
@LiteApplication Я обновил исходное сообщение, указав конфигурацию и код входа.
@AdityaDN Я обновил исходный пост. К сожалению, это происходит как с запросами GET, так и с POST, спасибо за эту ссылку, хотя попробовать стоило.
@Рубен, кажется, с кодом все в порядке, можешь попробовать if request.method == "POST"
отделить часть сообщения и удалить эти URL-адреса себе. Этот заблудший db.session.commit()
появился по ошибке, верно? Наконец, попробуйте установить app.config['SECRET_KEY']
на что-нибудь постоянное. IDK, если ничего из этого, возможно, проблема в конфигурации сервера.
@AdityaDN Случайный коммит — ошибка, я обновлю исходный пост. Я также пробовал менять секретные ключи. Основная проблема в том, что это может быть сделано на любой странице, а не только при входе в систему. Кроме того, пользователь на самом деле не вышел из системы, просто кажется, что пользователь не аутентифицирован, но затем обновляется одна и та же страница 1 или 2 раза, а затем отображается, что пользователь прошел аутентификацию без необходимости повторного входа в систему.
Удалось решить проблему. Оказывается, там остался некоторый код разработки;
with app.app_context():
db.reflect()
db.create_all()
Удаление решило все проблемы. Абсолютный кошмар, который нужно выследить.
Все еще ищу помощь по этому поводу, пожалуйста!