如何不使用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
相关产品推荐
相关产品推荐

