Django (v3.1) PASSWORD RESET LINK: django/contrib/auth/views.py 第 260 行的 AssertionError 在 kwargs 中断言 'uidb64' 并在 kwargs 中断言 'token'
Django (v3.1) PASSWORD RESET LINK: AssertionError at line 260 of django/contrib/auth/views.py assert 'uidb64' in kwargs and 'token' in kwargs
在 Django 3.1.2 中单击密码重置 link 时,我无法通过断言错误。我在 Docker 容器中安装了 Django 运行。
通过电子邮件发送的 link 似乎是正确的,因为它使用了正确的域 'localhost'。但是,在单击 link 后,错误消息将域 'localhost' 替换为 'Django:8000'。
HTML 文件
password_reset_email.html
{% load i18n %}{% autoescape off %}
{% trans "You're receiving this e-mail because you requested a password reset" %}
{% blocktrans %}for your user account at {{ site_name }}{% endblocktrans %}.
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb36=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The Super Awesome team{% endblocktrans %}
{% endautoescape %}
password_reset_confirm.html
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a> › {% trans 'Password reset confirmation' %}</div>{% endblock %}
{% block title %}{% trans 'Password reset' %}{% endblock %}
{% block content %}
{% if validlink %}
<h1>{% trans 'Enter new password' %}</h1>
<p>{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
<form action="" method="post">
{{ form.new_password1.errors }}
<p class="aligned wide"><label for="id_new_password1">{% trans 'New password:' %}</label>{{ form.new_password1 }}</p>
{{ form.new_password2.errors }}
<p class="aligned wide"><label for="id_new_password2">{% trans 'Confirm password:' %}</label>{{ form.new_password2 }}</p>
<p><input type="submit" value="{% trans 'Change my password' %}" /></p>
</form>
{% else %}
<h1>{% trans 'Password reset unsuccessful' %}</h1>
<p>{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}</p>
{% endif %}
{% endblock %}
URL 脚本:
urls.py
auth_patterns =
[
path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
re_path(r'^password_reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
]
完整错误回溯:
Environment:
Request Method: GET
Request URL: https://django:8000/accounts/password_reset/mjq5-ax0zta-7bba9cbeb8c411bfd0dcdee5d5ae10a6/
Django Version: 3.1.2
Python Version: 3.8.10
Installed Applications:
('django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.messages',
'django.contrib.sessions',
'django.contrib.staticfiles',
'django.contrib.admin',
'django.contrib.sites',
'formtools',
'django_extensions',
'template_utils',
'countries',
'pagination',
'seeker',
)
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'pagination.middleware.PaginationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'disc.middleware.LowerCaseMiddleware')
Traceback (most recent call last):
File "/root/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/root/.local/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/root/.local/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/views/decorators/debug.py", line 89, in sensitive_post_parameters_wrapper
return view(request, *args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/contrib/auth/views.py", line 260, in dispatch
assert 'uidb64' in kwargs and 'token' in kwargs
Exception Type: AssertionError at /accounts/password_reset/mjq5-ax0zta-7bba9cbeb8c411bfd0dcdee5d5ae10a6/
Exception Value:
docker-compose.yml
version: '3'
services:
django:
shm_size: 1g
build:
context: .
dockerfile: docker/django.dockerfile
env_file:
- .env
expose:
- "8000"
ports:
- "10080:8000"
volumes:
- ./run/django/data:/opt/data
- ./run/django/settings:/opt/settings
- ./media/:/media
- ./run/django/logs:/opt/logs
- /var/run/docker.sock:/var/run/docker.sock
healthcheck:
test: ["CMD", "curl", "-sf", "localhost:8000", "-o", "/dev/null"]
interval: 180s
timeout: 10s
retries: 3
nginx:
build:
context: docker/nginx
dockerfile: nginx.dockerfile
shm_size: 512m
environment:
- SSL_CERTIFICATE=${SSL_CERTIFICATE}
- DEPLOYMENT_DNS="${DEPLOYMENT_DNS:-localhost}"
ports:
- "${DISC_HTTP_PORT:-80}:80"
- "${DISC_HTTPS_PORT:-443}:443"
volumes:
- "${CREDENTIALS_PATH:-./run/nginx/credentials}:/credentials"
- "${LETSENCRYPT_CONFIG_PATH:-./run/nginx/letsencrypt/config}:/etc/letsencrypt"
- "${LETSENCRYPT_DATA_PATH:-./run/nginx/letsencrypt/data}:/data/letsencrypt"
- ./static:/static
- ./media/:/media
healthcheck:
test: ["CMD", "curl", "-sf", "--header", "Host: healthcheck.local", "localhost:80", "-o", "/dev/null"]
interval: 180s
timeout: 10s
retries: 3
depends_on:
- django
此 AssertionError 由 link 中的 url 模式导致 password_reset_confirm 调用 uidb36,而文件 "/root/.local/lib/python3.8 中的第 260 行/site-packages/django/contrib/auth/views.py", 专门寻找 uidb64 编码。 uidb36 编码是该项目年代久远的遗留片段,多年来已定期升级...
> 第 260 行: assert 'uidb64' in kwargs and 'token' in kwargs
> 将 link 更正为 password_reset_confirm:
re_path(r'^password_reset/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
注意,将密码重置确认link更改为uidb64后,如下,邮箱link也需要进行相应的更改: {{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
在 Django 3.1.2 中单击密码重置 link 时,我无法通过断言错误。我在 Docker 容器中安装了 Django 运行。
通过电子邮件发送的 link 似乎是正确的,因为它使用了正确的域 'localhost'。但是,在单击 link 后,错误消息将域 'localhost' 替换为 'Django:8000'。
HTML 文件
password_reset_email.html
{% load i18n %}{% autoescape off %}
{% trans "You're receiving this e-mail because you requested a password reset" %}
{% blocktrans %}for your user account at {{ site_name }}{% endblocktrans %}.
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb36=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The Super Awesome team{% endblocktrans %}
{% endautoescape %}
password_reset_confirm.html
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a> › {% trans 'Password reset confirmation' %}</div>{% endblock %}
{% block title %}{% trans 'Password reset' %}{% endblock %}
{% block content %}
{% if validlink %}
<h1>{% trans 'Enter new password' %}</h1>
<p>{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
<form action="" method="post">
{{ form.new_password1.errors }}
<p class="aligned wide"><label for="id_new_password1">{% trans 'New password:' %}</label>{{ form.new_password1 }}</p>
{{ form.new_password2.errors }}
<p class="aligned wide"><label for="id_new_password2">{% trans 'Confirm password:' %}</label>{{ form.new_password2 }}</p>
<p><input type="submit" value="{% trans 'Change my password' %}" /></p>
</form>
{% else %}
<h1>{% trans 'Password reset unsuccessful' %}</h1>
<p>{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}</p>
{% endif %}
{% endblock %}
URL 脚本:
urls.py
auth_patterns =
[
path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
re_path(r'^password_reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
]
完整错误回溯:
Environment:
Request Method: GET
Request URL: https://django:8000/accounts/password_reset/mjq5-ax0zta-7bba9cbeb8c411bfd0dcdee5d5ae10a6/
Django Version: 3.1.2
Python Version: 3.8.10
Installed Applications:
('django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.messages',
'django.contrib.sessions',
'django.contrib.staticfiles',
'django.contrib.admin',
'django.contrib.sites',
'formtools',
'django_extensions',
'template_utils',
'countries',
'pagination',
'seeker',
)
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'pagination.middleware.PaginationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'disc.middleware.LowerCaseMiddleware')
Traceback (most recent call last):
File "/root/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/root/.local/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/root/.local/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/views/decorators/debug.py", line 89, in sensitive_post_parameters_wrapper
return view(request, *args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/root/.local/lib/python3.8/site-packages/django/contrib/auth/views.py", line 260, in dispatch
assert 'uidb64' in kwargs and 'token' in kwargs
Exception Type: AssertionError at /accounts/password_reset/mjq5-ax0zta-7bba9cbeb8c411bfd0dcdee5d5ae10a6/
Exception Value:
docker-compose.yml
version: '3'
services:
django:
shm_size: 1g
build:
context: .
dockerfile: docker/django.dockerfile
env_file:
- .env
expose:
- "8000"
ports:
- "10080:8000"
volumes:
- ./run/django/data:/opt/data
- ./run/django/settings:/opt/settings
- ./media/:/media
- ./run/django/logs:/opt/logs
- /var/run/docker.sock:/var/run/docker.sock
healthcheck:
test: ["CMD", "curl", "-sf", "localhost:8000", "-o", "/dev/null"]
interval: 180s
timeout: 10s
retries: 3
nginx:
build:
context: docker/nginx
dockerfile: nginx.dockerfile
shm_size: 512m
environment:
- SSL_CERTIFICATE=${SSL_CERTIFICATE}
- DEPLOYMENT_DNS="${DEPLOYMENT_DNS:-localhost}"
ports:
- "${DISC_HTTP_PORT:-80}:80"
- "${DISC_HTTPS_PORT:-443}:443"
volumes:
- "${CREDENTIALS_PATH:-./run/nginx/credentials}:/credentials"
- "${LETSENCRYPT_CONFIG_PATH:-./run/nginx/letsencrypt/config}:/etc/letsencrypt"
- "${LETSENCRYPT_DATA_PATH:-./run/nginx/letsencrypt/data}:/data/letsencrypt"
- ./static:/static
- ./media/:/media
healthcheck:
test: ["CMD", "curl", "-sf", "--header", "Host: healthcheck.local", "localhost:80", "-o", "/dev/null"]
interval: 180s
timeout: 10s
retries: 3
depends_on:
- django
此 AssertionError 由 link 中的 url 模式导致 password_reset_confirm 调用 uidb36,而文件 "/root/.local/lib/python3.8 中的第 260 行/site-packages/django/contrib/auth/views.py", 专门寻找 uidb64 编码。 uidb36 编码是该项目年代久远的遗留片段,多年来已定期升级...
> 第 260 行: assert 'uidb64' in kwargs and 'token' in kwargs
> 将 link 更正为 password_reset_confirm:
re_path(r'^password_reset/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
注意,将密码重置确认link更改为uidb64后,如下,邮箱link也需要进行相应的更改: {{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}