You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:无法创建支持用户名或邮箱登录的Django登录表单

解决Django支持用户名/邮箱登录的表单输入类型及CSRF问题

核心问题拆解

你遇到的两个问题本质是:

  1. type="email" 的输入框会限制非邮箱格式的输入,无法兼容用户名;
  2. type="text" 输入邮箱时触发CSRF验证失败,但用户名登录正常,说明CSRF机制本身是有效的,问题出在输入邮箱时的请求异常。

第一步:解决输入类型兼容问题

直接使用 type="text" 作为登录标识的输入类型,同时添加提示文案让用户明确可输入用户名或邮箱,无需依赖浏览器的email类型校验(后端认证逻辑已经支持两种标识,前端不需要做格式限制)。

示例表单代码:

<form method="post" action="{% url 'login' %}">
    {% csrf_token %}
    <div>
        <label for="login_id">用户名/邮箱</label>
        <input type="text" id="login_id" name="login_id" autocomplete="off" required>
    </div>
    <div>
        <label for="password">密码</label>
        <input type="password" id="password" name="password" required>
    </div>
    <button type="submit">登录</button>
</form>

添加 autocomplete="off" 可以避免浏览器自动填充可能带来的请求干扰,这也是触发CSRF异常的常见诱因之一。


第二步:排查并修复CSRF验证失败问题

既然用户名登录正常,说明CSRF Token的生成和传递逻辑是对的,输入邮箱时的异常大概率是浏览器行为导致的,按以下步骤排查:

  1. 检查请求数据:打开浏览器开发者工具(F12)→ Network标签,提交邮箱登录请求后,查看Form Data中是否包含 csrfmiddlewaretoken 字段,且值与页面源代码中{% csrf_token %}生成的隐藏字段值一致。
  2. 查看Django错误日志:控制台会输出CSRF失败的具体原因,比如:
    • CSRF cookie not set.:检查浏览器是否允许站点Cookie,或是否有插件/JS阻止了Cookie写入;
    • Referer checking failed - no Referer.:确保请求的Referer头与站点域名一致(本地开发用localhost:8000时无需额外配置);
    • CSRF token missing or incorrect.:确认页面渲染时{% csrf_token %}没有被注释或遗漏。
  3. 清除浏览器缓存和Cookie:部分浏览器的自动填充缓存会导致请求数据异常,清除后重新测试。

确认自定义认证后端逻辑(参考)

确保你的认证后端正确处理用户名/邮箱两种查询逻辑,示例代码如下:

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q

UserModel = get_user_model()

class UsernameEmailAuthBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            # 同时匹配用户名或邮箱
            user = UserModel.objects.get(Q(username=username) | Q(email=username))
        except UserModel.DoesNotExist:
            return None
        except UserModel.MultipleObjectsReturned:
            user = UserModel.objects.filter(Q(username=username) | Q(email=username)).first()

        if user.check_password(password) and self.user_can_authenticate(user):
            return user

并在settings.py中配置认证后端:

AUTHENTICATION_BACKENDS = [
    'your_app.backends.UsernameEmailAuthBackend',
    'django.contrib.auth.backends.ModelBackend',
]

内容的提问来源于stack exchange,提问作者Vid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 16:24:13