Django REST-Auth重置密码链接含%20%0A,令牌无法正常使用求助
我之前帮几个开发者解决过这个一模一样的问题,咱们一步步来拆解问题成因和修复方案:
问题成因
这个编码问题的核心是密码重置链接里混入了空格(%20)和换行符(%0A),这些空白字符在生成URL时被自动编码了。具体来源通常有两个:
- django-rest-auth 0.9.5版本的默认邮件模板里,重置链接被换行/缩进处理了,导致生成的URL包含多余的空白;
- 你自定义的邮件发送逻辑(比如重写序列化器或视图时),不小心给链接添加了换行或空格。
看你提供的链接:http://127.0.0.1:8000/password-reset/confirm/MTY0MjM0MGMtNGEyMi00ZmY5LWE3YzgtNDdiOGM2M2ViYzIy/%20%0A%20%20%20%20%20%20%20%205d9-2e76cc7a3bc99cf6f1ed/,明显是令牌部分前面有换行和空格,这大概率是模板里的格式问题。
修复方案
1. 修复默认邮件模板(最直接有效)
django-rest-auth的默认密码重置模板路径是rest_auth/password_reset_email.html,你需要把这个模板拷贝到自己项目的templates目录下,然后修改链接部分,确保它是连续的一行,没有多余的空格或换行。
修改前的模板片段(可能存在的问题):
Please go to the following page and choose a new password: {{ protocol }}://{{ domain }}/{{ url|safe }}
这里的链接被单独换行,加上模板的缩进,会导致生成的URL带空白。
修改后的模板片段:
Please go to the following page and choose a new password: {{ protocol }}://{{ domain }}/{{ url|safe }}
或者把链接放在单独一行,但要保证链接本身没有被拆分、前后无多余空格:
Please go to the following page and choose a new password: {{ protocol }}://{{ domain }}/{{ url|safe }}
2. 重写PasswordResetSerializer确保链接无空白
如果你已经自定义了序列化器,检查get_email_options方法,确保传递给模板的参数没有引入空白。示例代码:
from rest_auth.serializers import PasswordResetSerializer class CustomPasswordResetSerializer(PasswordResetSerializer): def get_email_options(self): return { 'email_template_name': 'rest_auth/password_reset_email.html', # 确保所有参数(比如domain、protocol)没有多余空白 'extra_email_context': { 'domain': self.context['request'].get_host().strip(), 'protocol': 'https' if self.context['request'].is_secure() else 'http', } }
3. 手动清理链接中的空白字符(兜底方案)
如果上面的方法都没解决,可以在生成链接后手动去除空白。重写PasswordResetView的send_reset_email方法:
from rest_auth.views import PasswordResetView from django.core.mail import send_mail class CustomPasswordResetView(PasswordResetView): def send_reset_email(self, user): # 调用父类方法获取邮件内容的上下文 context = self.get_email_context(user) # 清理链接中的空白 context['url'] = context['url'].strip() # 重新构建邮件内容并发送 subject_template_name = 'rest_auth/password_reset_subject.txt' email_template_name = 'rest_auth/password_reset_email.html' subject = self.render_to_string(subject_template_name, context) subject = ''.join(subject.splitlines()) # 去除主题中的换行 email = self.render_to_string(email_template_name, context) send_mail(subject, email, None, [user.email])
总结
这个问题本质上是空白字符的编码问题,90%的情况都是邮件模板的格式导致的。先检查模板,把链接部分的多余空白去掉,基本就能解决。如果是自定义逻辑引入的空白,针对性清理即可。
内容的提问来源于stack exchange,提问作者TJA

