Аутентификация Django не работает с nginx и gunicorn, но работает с run_server

Я прочитал бесчисленное количество статей и перечитал эту проблему, но у меня пока нет ответа. У меня есть стандартная система, запущенная в docker с помощью docker-compose, которая имеет nginx в качестве обратного прокси для gunicorn и стандартную систему аутентификации django. Я переделал страницы входа, установив классы форм, но это все, что я могу настроить.

Когда я запускаю свой сайт в run_server для его отладки, все работает. Я перехожу на страницу входа, успешно вхожу и получаю перенаправление. is_authenticated дает исключительные результаты. Я запускаю точно такие же страницы на nginx и gunicorn и получаю очень странное поведение. Часто я успешно вхожу в систему, мой sessionid совпадает с сессией в базе данных, токен csrf совпадает с тем, что находится в базе данных, но is_authenticated оказывается ложным. Но только около 90% времени. Часто я попадаю на страницу, которая требует входа, используя декоратор login_required на url (login_required(view.as_view())), и мне приходится входить несколько раз, is_authenticated false каждый раз, пока это не сработает, а когда это сработает, is_authenticated устанавливается в false, как только я перехожу на страницу входа.

Вот моя конфигурация nginx. Обратите внимание, что django - это ip-адрес, назначенный docker-compose, а gunicorn работает на порту 8050. Это действительно стандартно для этого:

server {
    listen       80;
    server_name  _;

    #charset koi8-r;
    access_log  /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    #location / {
    #    root   /usr/share/nginx/html;
    #    index  index.html index.htm;
    #}

    location /static/ {
        autoindex on;
        alias /static/;
    }

    location /pgadmin4/ {
        # forward application requests to the gunicorn server

        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Script-Name /pgadmin4;

        # Changing timeout behavior
        proxy_read_timeout 300;
        proxy_pass http://pgadmin;
    }

    location / {
        # forward application requests to the gunicorn server
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # Changing timeout behavior
        proxy_read_timeout 300;
        proxy_pass http://django:8050;
    }
}

Вот соответствующая часть settings.py

INSTALLED_APPS = [
    'cvi.apps.CviConfig',
    'crispy_forms',
    'notes.apps.NotesConfig',
    'scenarios.apps.ScenariosConfig',
    'tsmodels.apps.TsmodelsConfig',
    'services.apps.ServicesConfig',
    'model_info.apps.ModelInfoConfig',
    'data_tools.apps.DataToolsConfig',
    'demos.apps.DemosConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'bootstrap_datepicker_plus',
    'wkhtmltopdf'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

WSGI_APPLICATION = 'DataManagement.wsgi.application'

А вот скрипт запуска gunicorn:

exec gunicorn DataManagement.wsgi:application \
    --name=DataManagement \
    --workers=4 \
    --log-level=debug \
    --bind=0.0.0.0:8050 \
    --timeout=600 \
    --log-file=./gunicorn.log \
    --log-level=debug

Эта конфигурация работает без аутентификации. Второй раз я добавил login_required к моим урлам, когда возникла проблема с аутентификацией. Я буду очень признателен за любую помощь, которую вы можете оказать. Я никогда не сталкивался с этой проблемой раньше, когда настраивал аутентификацию пользователей на других сайтах django.

Проблема заключается в отсутствии документации и вариантов конфигурации. Мы использовали SECRET_KEY в django, очевидно, не скопированный сюда. Согласно документации, у нас есть get_random_secret_key() для среды разработки. Это не работает с несколькими рабочими в gunicorn. Каждый рабочий будет запускать новый терминал и, следовательно, получать новый SECRET_KEY для каждого рабочего. Секретный ключ, очевидно, используется где-то в системе аутентификации django. У вас нет контроля над тем, какой рабочий получает ваш запрос от nginx, поэтому возможно, что у вас один рабочий для 3 или 4 ваших запросов или 4 рабочих для ваших 4 запросов. Есть несколько вариантов, как это исправить.

  1. Используйте фиксированный секретный ключ. Рабочие запускаются с одним и тем же ключом, и это, похоже, работает.
  2. .
  3. Используйте один рабочий с несколькими потоками и gthread в качестве рабочего класса gunicorn. Нити одного рабочего будут наследовать секретный ключ.
  4. .

Это не документировано в django или gunicorn, и рабочие примеры по умолчанию будут неудачными. Вот пример команды gunicorn, которую я использую для запуска контейнера django:

exec gunicorn DataManagement.wsgi:application \
     --name=DataManagement \
     --workers=1 \
     --log-level=debug \
     --bind=0.0.0.0:8050 \
     --timeout=600 \
     --log-file=./gunicorn.log \
     --log-level=debug \
     --worker-class=gthread \
     --threads=16

`

Вернуться на верх