Вход в Django будет проходить аутентификацию, но перенаправление завершится неудачно только на удаленном сервере - PullRequest
2 голосов
/ 11 июля 2019

Я только что закончил создание своего веб-приложения и перенес его в цифровую каплю океана. Проблема, с которой я сталкиваюсь, заключается в том, что я могу запустить runserver 0.0.0.0:8000 и использовать свой IP-адрес сервера, чтобы попасть на мою домашнюю страницу, целевую страницу, зарегистрироваться и т. Д. Кроме того, я могу ввести неправильные учетные данные и быть перенаправлен обратно для повторного входа. Как только введены правильные учетные данные, Django вешает трубку, пока я не остановлю сервер.

На моей локальной машине у меня нет этой проблемы, так как при подключении через локальную сеть я могу успешно войти в систему. Мой локальный компьютер подключается к базе данных в капельке в том же центре обработки данных, что и мой сервер Django Prod.

Странно, согласно моей базе данных, попытка входа в систему успешна. Кажется, проблема связана с перенаправлением на мой взгляд. изменив перенаправление на целевую страницу и добавив операторы печати в свое представление, я вижу, что к нему никогда не будет доступа после аутентификации.

Версия Mysql идентична в обоих случаях.

Из моего экземпляра Django:

  • Я могу войти в базу данных из своего экземпляра
  • Я могу создать нового суперпользователя из своего экземпляра manage.py shell
  • Я могу заполнить форму регистрации и создать нового пользователя (но моя оболочка зависает до CTR + C)
  • Я могу войти и доказать, что я аутентифицирован с manage.py shell
  • Я могу подтвердить, что мой сервер не удаляет мои заголовки
  • Я могу запросить у моих пользователей manage.py shell
  • Я не получаю никаких ошибок
  • мой сервер не использует слишком много CPU
  • allowed_hosts = [ '*']
  • Я закомментировал все функции безопасности
  • NGINX и Gunicorn отключены (та же проблема существует, если они включены)

Также я клонировал свой репо в том же экземпляре, что и моя база данных. к сожалению, это не решило мою проблему.

Я использую: python3.6.8 - Django 2.2.1 - MySQL 5.7

settings.py

import os
 
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


SECRET_KEY = os.environ['SECRET_KEY']

DEBUG = True

ALLOWED_HOSTS = ['*']


# Application definition

INSTALLED_APPS = [
    #django builtin Imports
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites',

    #django installed pacakges imports
    'allauth',
    'allauth.account',
    'crispy_forms',
    'jquery',
    'rest_framework',
    'rest_framework_datatables',
    'chartjs',
    'sass_processor',
    'django_nose',

    #user built imports
    'users',
    'pages',
    'authenticated',
    'exchange',
    'celerytasks'

]

    REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
        'rest_framework_datatables.renderers.DatatablesRenderer',
    ),
    'DEFAULT_FILTER_BACKENDS': (
        'rest_framework_datatables.filters.DatatablesFilterBackend',
    ),
    'DEFAULT_PAGINATION_CLASS': (
                  'rest_framework_datatables.pagination.DatatablesPageNumberPagination'
        ),
    'PAGE_SIZE': 3,
}


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',
    'django.contrib.auth.middleware.RemoteUserMiddleware',
]

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'


ROOT_URLCONF = 'rubillion.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'libraries':{
                'file_exists': 'authenticated.templatetags.app_filters'
            },
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'rubillion.wsgi.application'

#SESSION_ENGINE = "django.contrib.sessions.backends.cache" 

DATABASES = {
    'default': {
        'HOST': os.environ['HOST'],
        'NAME': 'user_db',
        'ENGINE': 'django.db.backends.mysql',
        'USER': os.environ['DBUSER'],
        'PASSWORD': os.environ['DBPWD']
    },
    'auth_db': {
        'HOST': os.environ['HOST'],
        'NAME': 'user_db',
        'ENGINE': 'django.db.backends.mysql',
        'USER': os.environ['DBUSER'],
        'PASSWORD': os.environ['DBPWD']
    },
    'exchange_db': {
        'HOST': os.environ['HOST'],
        'NAME': 'exchange',
        'ENGINE': 'django.db.backends.mysql',
        'USER': os.environ['DBUSER'],
        'PASSWORD': os.environ['DBPWD']
    },
}

DATABASE_ROUTERS = ['rubillion.routers.ExchangeRouter',     'rubillion.routers.AuthRouter']
# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-    validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME':     'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static")
]

AUTH_USER_MODEL = 'users.CustomUser'

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

LOGIN_REDIRECT_URL = 'pages:home'
ACCOUNT_LOGOUT_REDIRECT_URL = 'pages:home'

AUTHENTICATION_BACKENDS = (
    "django.contrib.auth.backends.RemoteUserBackend",
    "allauth.account.auth_backends.AuthenticationBackend",
    "django.contrib.auth.backends.ModelBackend",
)

SITE_ID = 1

ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_SIGNUP_FORM_CLASS = "users.forms.CustomUserCreationForm"
ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE = False
ACCOUNT_SESSION_REMEMBER = True
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_UNIQUE_EMAIL = True

CRISPY_TEMPLATdE_PACK = 'bootstrap4'


MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'


'''
    --------------------------------------------------
    
    ALL SECURITY CONCERNS MUST BE ADDRESSED BELOW THIS LINE

    --------------------------------------------------
'''
#SECURE_BROWSER_XSS_FILTER = True
#SECURE_CONTENT_TYPE_NOSNIFF = True
#SECURE_HSTS_INCLUDE_SUBDOMAINS = True
#SECURE_SSL_REDIRECT = True
#SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
#SESSION_COOKIE_SECURE = False
#CSRF_COOKIE_SECURE = True
#SECURE_HSTS_SECONDS = 60

#PREPEND_WWW = True
#BASE_URL = "https://###"

#X_FRAME_OPTIONS = 'DENY'
#SECURE_HSTS_PRELOAD = True
wsgi.py

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rubillion.settings')

application = get_wsgi_application()

релевантный urls.py

from django.urls import path, include, re_path
from .views import *
from rest_framework import routers, renderers


app_name = "pages"
router = routers.DefaultRouter())

urlpatterns = [
    path('', HomePageView.as_view(), name='home'),
]

Как я создал суперпользователя и проверь, существуют ли они

(rubyenv)$ python3 manage.py shell
>>> from users.models import CustomUser;
>>> CustomUser.objects.create_superuser('admin', 'a@gmail.com',       '$Admin11')


(rubyenv)$ python3 manage.py shell
>>> from users.models import CustomUser
>>> c = CustomUser.objects.filter(is_superuser=True)
>>> print(c)
<QuerySet [
    <CustomUser: **@gmail.com>, 
    <CustomUser: admin@example.com>, 
    <CustomUser: **@test.com>
    ]>

Вид моей домашней страницы, который перенаправляется. Я добавил два оператора печати, чтобы убедиться, что заголовки совпадают с заголовками на моем локальном компьютере.

class HomePageView(TemplateView):
    template_name = 'pages/home.html'

    def get(self, request):
        #print(request.headers)
        #print(request.META)
        return render(request, self.template_name, {})

Мой журнал ошибок, когда мне нужно отменить create_superuser (Пользователь создается независимо)

 File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/contrib/auth/models.py", line 162, in create_superuser
    return self._create_user(username, email, password, **extra_fields)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/contrib/auth/models.py", line 145, in _create_user
    user.save(using=self._db)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/contrib/auth/base_user.py", line 66, in save
    super().save(*args, **kwargs)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/base.py", line 741, in save
    force_update=force_update, update_fields=update_fields)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/base.py", line 790, in save_base
    update_fields=update_fields, raw=raw, using=using,
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in send
    for receiver in self._live_receivers(sender)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
    for receiver in self._live_receivers(sender)
  File "/home/antony/ruby/authenticated/models.py", line 320, in create_user_profile
    Users.objects.get_or_create(username=instance)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/query.py", line 541, in get_or_create
    return self._create_object_from_params(kwargs, params)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/query.py", line 575, in _create_object_from_params
    obj = self.create(**params)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/query.py", line 422, in create
    obj.save(force_insert=True, using=self.db)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/base.py", line 741, in save
    force_update=force_update, update_fields=update_fields)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/base.py", line 790, in save_base
    update_fields=update_fields, raw=raw, using=using,
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in send
    for receiver in self._live_receivers(sender)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
    for receiver in self._live_receivers(sender)
  File "/home/antony/ruby/exchange/models.py", line 49, in queue_task
    send_task('celerytasks.tasks.volatilityTrader')
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/celery/local.py", line 191, in __call__
    return self._get_current_object()(*a, **kw)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/celery/app/base.py", line 756, in send_task
    amqp.send_task_message(P, name, message, **options)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/celery/app/amqp.py", line 552, in send_task_message
    **properties
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/messaging.py", line 181, in publish
    exchange_name, declare,
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/connection.py", line 510, in _ensured
    return fun(*args, **kwargs)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/messaging.py", line 187, in _publish
    channel = self.channel
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/messaging.py", line 209, in _get_channel
    channel = self._channel = channel()
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/utils/functional.py", line 44, in __call__
    value = self.__value__ = self.__contract__()
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/messaging.py", line 224, in <lambda>
    channel = ChannelPromise(lambda: connection.default_channel)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/connection.py", line 852, in default_channel
    self.ensure_connection(**conn_opts)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/connection.py", line 422, in ensure_connection
    callback, timeout=timeout)
  File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/utils/functional.py", line 355, in retry_over_time
    sleep(1.0)

Я рассмотрел все вопросы о переполнении стека, которые мог найти, и попробовал то, что чувствуется как каждое решение. Я устранял эту проблему в течение 4 дней, и мне отчаянно нужна помощь. Если есть какая-либо информация, которую я забыл предоставить, пожалуйста, дайте мне знать:)

РЕШИТЬ:
Как указывает Сидней Перейра, ответ на этот вопрос связан с сельдереем.

Я не настроил rabbitmq на моем удаленном сервере . Я ждал, чтобы сначала завершить настройку Gunicorn и Nginx, и он мне не понадобился для аутентификации. В другом приложении exchange/models.py

Я использовал декоратор получателя и опустил sender = model_name. Я планировал запустить задачу сельдерея, когда новые записи цен добавляются в БД. Вместо этого это событие будет запускаться каждый раз, когда любая запись добавляется в db

.

class Price(models.Model):
    ModelField
    ModelField
    objects = models.Manager()

    def __str__(self):
        return self.pair + ' / ' + str(self.timestamp)

    @receiver(post_save)
    def queue_task(instance, created, **kwargs):
        send_task('celerytasks.tasks.volatilityTrader')
        send_task('celerytasks.tasks.swingTrader')

    class Meta:
        managed = False
 

Решение:

  class Price(models.Model):
    ModelField
    ModelField
    objects = models.Manager()

    def __str__(self):
        return self.pair + ' / ' + str(self.timestamp)

    class Meta:
        managed = False
 
#reciever must go after model is defined and a sender arg is required

@receiver(post_save, sender=Price)
def queue_task(instance, created, **kwargs):
    send_task('celerytasks.tasks.volatilityTrader')
    send_task('celerytasks.tasks.swingTrader')
        

1 Ответ

1 голос
/ 13 июля 2019

По трассировке я полагаю, что к моменту входа в систему вы используете сельдерей для асинхронной задачи. Эта задача сельдерея, похоже, запускается сигналом Django при сохранении модели User. Поскольку он долго зависает, я думаю, это потому, что когда вы отправляете сообщение брокеру, он не может его достать. Это может означать, что Celery не настроен должным образом (или не настроен вообще) в этой удаленной среде, или не работает брокер сообщений, к которому он подключается (RabbitMQ, Redis, SQS, Kafka и т. Д.).

Что ж, если вы не имеете представления об использовании сельдерея (я полагаю, вы понимаете это, поскольку он находится в INSTALLED_APPS) в проекте - например, "он работает нормально, если никакой брокер не работает в локальной среде", что означает, что некоторые отладочные флаги игнорируются это - я думаю, что другой пакет, который вы используете, зависит от Celery.

Некоторые вещи для отладки:

File "/home/antony/ruby/authenticated/models.py", line 320, in create_user_profile
Users.objects.get_or_create(username=instance)

Похоже, это выполняется из-за сигнала Джанго

File "/home/antony/ruby/exchange/models.py", line 49, in queue_task
    send_task('celerytasks.tasks.volatilityTrader')

См? Здесь сообщение / задача отправляется в очередь брокера, поэтому используется сетевое соединение (если вы не используете CELERY_TASK_ALWAYS_EAGER), вероятно, поэтому сервер никогда не отвечает.

...