无法覆盖 AWS 中的 Django 身份验证模板
Cannot overwrite Django authentication templates in AWS
我开发了一个 Django 应用程序,我一直在使用 django-authtools 模块来使用电子邮件登录。它在我的笔记本电脑上运行良好,但当我尝试使用 Beanstalk 在 AWS 的生产环境中部署它时,Django 似乎无法识别身份验证模块的覆盖,并强制重定向到 django 内置身份验证模块。其他一切似乎都工作正常(从部署和应用程序的角度来看)。
它导致 500 错误:
xxx.xxx.xxx.xxx (-) - - [04/Jul/2017:19:07:54 +1000] "GET /accounts/login/ HTTP/1.1" 500 7807 "http://<removed>.ap-southeast-2.elasticbeanstalk.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"
Internal Server Error: /accounts/login/
Traceback (most recent call last):
File "/opt/python/run/venv/lib/python3.4/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/opt/python/run/venv/lib/python3.4/site-packages/django/core/handlers/base.py", line 217, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/opt/python/run/venv/lib/python3.4/site-packages/django/core/handlers/base.py", line 215, in _get_response
response = response.render()
File "/opt/python/run/venv/lib/python3.4/site-packages/django/template/response.py", line 107, in render
self.content = self.rendered_content
File "/opt/python/run/venv/lib/python3.4/site-packages/django/template/response.py", line 82, in rendered_content
template = self.resolve_template(self.template_name)
File "/opt/python/run/venv/lib/python3.4/site-packages/django/template/response.py", line 64, in resolve_template
return select_template(template, using=self.using)
File "/opt/python/run/venv/lib/python3.4/site-packages/django/template/loader.py", line 53, in select_template
raise TemplateDoesNotExist(', '.join(template_name_list), chain=chain)
django.template.exceptions.TemplateDoesNotExist: registration/login.html
同样,这在我的笔记本电脑上运行良好,但在 AWS 服务器上运行不正常。我找不到两者之间的任何区别,它们是 运行 相同版本的 django 和 django-authools:
$ pip freeze
[...]
Django==1.11.2
django-authtools==1.5.0
django-extensions==1.7.6
django-phonenumber-field==1.3.0
django-qsstats-magic==0.7.2
django-simple-captcha==0.5.5
django-storages==1.6.1
[...]
唯一的区别似乎是 python 的版本,在 AWS 上是 3.4.3,在我的笔记本电脑上是 3.5.2。
在服务器上,我的 settings.py 文件与笔记本电脑上的相同:
myproject/settings.py:
INSTALLED_APPS = [
'myapp.apps.MyappConfig',
'authtools',
'captcha',
'storages',
'phonenumber_field',
'django_extensions',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
AUTH_USER_MODEL = "authtools.User"
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
myapp/urls.py:
from authtools import urls
[...]
url(r'^accounts/', include('authtools.urls')),
[...]
authtools/url.py:
from django.conf.urls import url
from authtools import views as authools_views
urlpatterns = [
url(r'^login/$', authools_views.LoginView.as_view(), name='login'),
url(r'^logout/$', authools_views.LogoutView.as_view(), {'next_page': '/accounts/login'}, name='logout'),
url(r'^password_change/$', authools_views.PasswordChangeView.as_view(), name='password_change'),
url(r'^password_change/done/$', authools_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
url(r'^password_reset/$', authools_views.PasswordResetView.as_view(), name='password_reset'),
url(r'^password_reset/done/$', authools_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
url(r'^reset/done/$', authools_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
url(r'^reset/(?P<uidb36>[0-9A-Za-z]{1,13})-(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
authools_views.PasswordResetConfirmView.as_view()),
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
authools_views.PasswordResetConfirmView.as_view(),
name='password_reset_confirm'),
]
我也试过直接在url语句中传递模板(LoginView.as_view(template_name='myapp/login.html'))但结果相同
authtools/view.py 的摘录:
class LoginView(AuthDecoratorsMixin, WithCurrentSiteMixin, WithNextUrlMixin, FormView):
print('ENTERING LOGIN VIEW')
form_class = AuthenticationForm
template_name = 'myapp/login.html'
allow_authenticated = True
success_url = resolve_url_lazy(settings.LOGIN_REDIRECT_URL)
# BBB: This is deprecated (See LoginView.get_allow_authenticated)
disallow_authenticated = None
错误 "registration/login.html" 中显示的模板是内置模板,而不是 authtools 模块提供的应该覆盖它的模板。
此外,当导航到我网站的 /admin/ 时,我可以使用我的超级用户正确登录,当返回该网站时,我会被检测为已通过身份验证。注销操作虽然将我重定向到默认注销页面,但没有使用 authtools 模块中提供的自定义模板(同样的行为)。
如果有人有解决方案或任何关于在哪里调查的想法,我们将不胜感激!
谢谢!
我正在添加我的 beantalk 配置文件以防万一,尽管我不认为这是与 beantalk 本身相关的问题。
.ebextensions# cat 001_set_env.config
option_settings:
"aws:elasticbeanstalk:application:environment":
PYTHONPATH: /opt/python/current/app/myapp:/opt/python/current/app/authtools:$PYTHONPATH
"aws:elasticbeanstalk:container:python":
WSGIPath: "myproject/wsgi.py"
.ebextensions# cat 002_deploy.config
commands:
01_update_pip:
command: "/opt/python/run/venv/bin/pip install --upgrade pip"
02_set_time_zone:
command: ln -f -s /usr/share/zoneinfo/Australia/Sydney /etc/localtime
container_commands:
01_makemigration:
command: "source /opt/python/run/venv/bin/activate && python manage.py makemigrations --noinput"
leader_only: true
02_migrate:
command: "source /opt/python/run/venv/bin/activate && python manage.py migrate --noinput"
leader_only: true
03_initialize_db:
command: "source /opt/python/run/venv/bin/activate && python manage.py initializedb"
leader_only: true
04_create_superuser:
command: "source /opt/python/run/venv/bin/activate && python manage.py createsu"
leader_only: true
我建议您停止编辑 authtools
中的代码。不清楚你是怎么做的,因为错误显示缺少的模板是 registration/login.html
,它现在正在生产中工作。
如果您将模板从 myapp/templates/myapp/login.html
重命名为 myapp/templates/registration/login.html
,应用程序目录加载程序应该会找到您的模板。
最后,顺便说一下,您的 DIRS
设置看起来不正确。
'DIRS': ['templates'],
如果要包含 myproject/templates
目录,请将其更改为
'DIRS': [os.path.join(BASE_DIR, 'templates')]
对于那些感兴趣的人,我终于找到了这个问题的问题。我在 site_packages 和本地项目中都安装了 authools 模块。在我的本地笔记本电脑上,优先顺序似乎是首先查看我的本地 django 项目(我的模块具有正确的模板路径),而在 AWS 上,列出的 python 路径顺序 site_packages首先,因此查看 authtools 的未修改版本。
因此,我删除了安装在我的项目中的 authtools 版本,我现在使用安装在 site_packages 中的原始版本,同时直接在我的应用 urls.py 中覆盖 authools 模板名称。
感谢大家的帮助,让我走上正轨。
我开发了一个 Django 应用程序,我一直在使用 django-authtools 模块来使用电子邮件登录。它在我的笔记本电脑上运行良好,但当我尝试使用 Beanstalk 在 AWS 的生产环境中部署它时,Django 似乎无法识别身份验证模块的覆盖,并强制重定向到 django 内置身份验证模块。其他一切似乎都工作正常(从部署和应用程序的角度来看)。 它导致 500 错误:
xxx.xxx.xxx.xxx (-) - - [04/Jul/2017:19:07:54 +1000] "GET /accounts/login/ HTTP/1.1" 500 7807 "http://<removed>.ap-southeast-2.elasticbeanstalk.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"
Internal Server Error: /accounts/login/
Traceback (most recent call last):
File "/opt/python/run/venv/lib/python3.4/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/opt/python/run/venv/lib/python3.4/site-packages/django/core/handlers/base.py", line 217, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/opt/python/run/venv/lib/python3.4/site-packages/django/core/handlers/base.py", line 215, in _get_response
response = response.render()
File "/opt/python/run/venv/lib/python3.4/site-packages/django/template/response.py", line 107, in render
self.content = self.rendered_content
File "/opt/python/run/venv/lib/python3.4/site-packages/django/template/response.py", line 82, in rendered_content
template = self.resolve_template(self.template_name)
File "/opt/python/run/venv/lib/python3.4/site-packages/django/template/response.py", line 64, in resolve_template
return select_template(template, using=self.using)
File "/opt/python/run/venv/lib/python3.4/site-packages/django/template/loader.py", line 53, in select_template
raise TemplateDoesNotExist(', '.join(template_name_list), chain=chain)
django.template.exceptions.TemplateDoesNotExist: registration/login.html
同样,这在我的笔记本电脑上运行良好,但在 AWS 服务器上运行不正常。我找不到两者之间的任何区别,它们是 运行 相同版本的 django 和 django-authools:
$ pip freeze
[...]
Django==1.11.2
django-authtools==1.5.0
django-extensions==1.7.6
django-phonenumber-field==1.3.0
django-qsstats-magic==0.7.2
django-simple-captcha==0.5.5
django-storages==1.6.1
[...]
唯一的区别似乎是 python 的版本,在 AWS 上是 3.4.3,在我的笔记本电脑上是 3.5.2。
在服务器上,我的 settings.py 文件与笔记本电脑上的相同:
myproject/settings.py:
INSTALLED_APPS = [
'myapp.apps.MyappConfig',
'authtools',
'captcha',
'storages',
'phonenumber_field',
'django_extensions',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
AUTH_USER_MODEL = "authtools.User"
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
}, ]
myapp/urls.py:
from authtools import urls
[...]
url(r'^accounts/', include('authtools.urls')),
[...]
authtools/url.py:
from django.conf.urls import url
from authtools import views as authools_views
urlpatterns = [
url(r'^login/$', authools_views.LoginView.as_view(), name='login'),
url(r'^logout/$', authools_views.LogoutView.as_view(), {'next_page': '/accounts/login'}, name='logout'),
url(r'^password_change/$', authools_views.PasswordChangeView.as_view(), name='password_change'),
url(r'^password_change/done/$', authools_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
url(r'^password_reset/$', authools_views.PasswordResetView.as_view(), name='password_reset'),
url(r'^password_reset/done/$', authools_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
url(r'^reset/done/$', authools_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
url(r'^reset/(?P<uidb36>[0-9A-Za-z]{1,13})-(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
authools_views.PasswordResetConfirmView.as_view()),
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
authools_views.PasswordResetConfirmView.as_view(),
name='password_reset_confirm'),
]
我也试过直接在url语句中传递模板(LoginView.as_view(template_name='myapp/login.html'))但结果相同
authtools/view.py 的摘录:
class LoginView(AuthDecoratorsMixin, WithCurrentSiteMixin, WithNextUrlMixin, FormView):
print('ENTERING LOGIN VIEW')
form_class = AuthenticationForm
template_name = 'myapp/login.html'
allow_authenticated = True
success_url = resolve_url_lazy(settings.LOGIN_REDIRECT_URL)
# BBB: This is deprecated (See LoginView.get_allow_authenticated)
disallow_authenticated = None
错误 "registration/login.html" 中显示的模板是内置模板,而不是 authtools 模块提供的应该覆盖它的模板。 此外,当导航到我网站的 /admin/ 时,我可以使用我的超级用户正确登录,当返回该网站时,我会被检测为已通过身份验证。注销操作虽然将我重定向到默认注销页面,但没有使用 authtools 模块中提供的自定义模板(同样的行为)。
如果有人有解决方案或任何关于在哪里调查的想法,我们将不胜感激!
谢谢!
我正在添加我的 beantalk 配置文件以防万一,尽管我不认为这是与 beantalk 本身相关的问题。
.ebextensions# cat 001_set_env.config
option_settings:
"aws:elasticbeanstalk:application:environment":
PYTHONPATH: /opt/python/current/app/myapp:/opt/python/current/app/authtools:$PYTHONPATH
"aws:elasticbeanstalk:container:python":
WSGIPath: "myproject/wsgi.py"
.ebextensions# cat 002_deploy.config
commands:
01_update_pip:
command: "/opt/python/run/venv/bin/pip install --upgrade pip"
02_set_time_zone:
command: ln -f -s /usr/share/zoneinfo/Australia/Sydney /etc/localtime
container_commands:
01_makemigration:
command: "source /opt/python/run/venv/bin/activate && python manage.py makemigrations --noinput"
leader_only: true
02_migrate:
command: "source /opt/python/run/venv/bin/activate && python manage.py migrate --noinput"
leader_only: true
03_initialize_db:
command: "source /opt/python/run/venv/bin/activate && python manage.py initializedb"
leader_only: true
04_create_superuser:
command: "source /opt/python/run/venv/bin/activate && python manage.py createsu"
leader_only: true
我建议您停止编辑 authtools
中的代码。不清楚你是怎么做的,因为错误显示缺少的模板是 registration/login.html
,它现在正在生产中工作。
如果您将模板从 myapp/templates/myapp/login.html
重命名为 myapp/templates/registration/login.html
,应用程序目录加载程序应该会找到您的模板。
最后,顺便说一下,您的 DIRS
设置看起来不正确。
'DIRS': ['templates'],
如果要包含 myproject/templates
目录,请将其更改为
'DIRS': [os.path.join(BASE_DIR, 'templates')]
对于那些感兴趣的人,我终于找到了这个问题的问题。我在 site_packages 和本地项目中都安装了 authools 模块。在我的本地笔记本电脑上,优先顺序似乎是首先查看我的本地 django 项目(我的模块具有正确的模板路径),而在 AWS 上,列出的 python 路径顺序 site_packages首先,因此查看 authtools 的未修改版本。 因此,我删除了安装在我的项目中的 authtools 版本,我现在使用安装在 site_packages 中的原始版本,同时直接在我的应用 urls.py 中覆盖 authools 模板名称。
感谢大家的帮助,让我走上正轨。