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

如何不使用Django默认登录表单实现自定义登录及报错解决

解决 Django 自定义登录/注册的 MultiValueDictKeyError 及登录功能实现问题

1. 先搞定 registerUser 视图的 MultiValueDictKeyError 错误

你碰到的这个错误核心原因是视图逻辑顺序完全搞反了:你在判断请求是否为 POST 之前,就直接从request.POST里取username数据。当用户用 GET 请求访问注册页面时,request.POST是空的,自然找不到username这个键,直接抛出异常。

修改后的registerUser视图代码:

def registerUser(request):
    if request.method == 'POST':
        # 只有POST请求才处理表单数据,用get方法更安全,避免键不存在直接报错
        username = request.POST.get('username')
        email = request.POST.get('email')
        password = request.POST.get('password')
        
        # 先检查用户名是否已存在
        if User.objects.filter(username=username).exists():
            return HttpResponse("Username already Exists")
        
        # 生成盐值和哈希密码
        salt = os.urandom(32)
        key = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, 100000)
        hashPassword = salt + key
        
        # 创建并保存用户
        user = User(username=username, email=email, password=password, hashedPassword=hashPassword)
        user.save()
        context = {'username': username}
        return render(request, "success.html", context)
    else:
        # GET请求返回注册页面(这里你应该返回自己的注册表单页面,比如register.html)
        return render(request, "register.html")

2. 修正登录表单的提交目标

你的登录表单action指向了successURL,但实际上应该指向处理登录逻辑的loginCredentials视图对应的URL,同时别忘了显式指定method="POST"(默认是GET,会把密码拼在URL里,既不安全也不符合视图逻辑)。修改Login.html的表单:

<form action="{% url 'loginCredentials' %}" method="POST" id="Myform"> 
    {% csrf_token %} 
    <label>Username: <input type="text" placeholder="Enter Your Username" id="input" name="userUsername"> </label><br> 
    <label>Password: <input type="password" placeholder="Enter Your Password" id="input" name="userPassword"> </label><br> 
    <a href="{% url 'register' %}" style="float: right;">Didn't Have Account?</a><br><br> 
    <button class="btn-success" id="button">Log In</button> 
</form>

3. 修复 loginCredentials 的登录验证逻辑

你的登录逻辑有几个致命问题:每次登录都生成新的salt,用这个新salt计算的哈希永远不可能和数据库里存储的(旧salt+key)匹配;用User.objects.get()查询不存在的用户会直接抛出500异常;单独查询hashedPassword的逻辑完全错误。

修改后的loginCredentials视图:

def loginCredentials(request):
    if request.method == 'POST':
        username = request.POST.get('userUsername')
        password = request.POST.get('userPassword')
        
        # 先尝试根据用户名获取用户,处理用户不存在的情况
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            # 用户不存在,返回登录页并提示错误(可以在模板里加错误提示)
            return render(request, "login.html", {'error': 'Invalid username or password'})
        
        # 从用户对象中取出存储的salt和哈希密码(你存储的是salt(32位)+key,所以前32位是salt)
        stored_hash = user.hashedPassword
        salt = stored_hash[:32]
        stored_key = stored_hash[32:]
        
        # 用用户的salt重新计算输入密码的哈希
        key = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, 100000)
        
        # 对比计算出的key和存储的key
        if key == stored_key:
            # 登录成功,跳转到success页面
            return render(request, "success.html", {'username': username})
        else:
            # 密码错误,返回登录页
            return render(request, "login.html", {'error': 'Invalid username or password'})
    else:
        # GET请求返回登录页面
        return render(request, "login.html")

4. 额外优化建议

  • 尽量使用Django自带的User模型或者自定义AbstractUser,Django已经封装了安全的密码哈希逻辑,自己手动实现很容易出现安全漏洞;
  • 在登录模板里添加错误提示,比如在login.html里加:
    {% if error %}
        <p style="color: red;">{{ error }}</p>
    {% endif %}
    
  • 对表单输入做校验(比如用户名长度、密码强度等),可以用Django的表单类(forms.Form或forms.ModelForm)来简化校验逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 15:52:45