Django自定义Token登录系统报错排查及用户目的地过滤求助
问题排查与解决方案
错误原因分析
- NOT NULL约束失败:Session模型中
user是OneToOneField(非空约束),但登录视图里先创建Session对象却未关联用户,直接触发数据库非空校验错误;且Session创建逻辑放在用户验证之前,无论用户是否合法都会生成无效Session。 - 密码验证逻辑错误:User模型的
check_password方法逻辑颠倒——将数据库中已存储的哈希密码再次哈希,再与传入的哈希密码对比,永远无法匹配。
代码修复方案
1. 修复User模型的密码验证方法
from django.db import models import hashlib class User(models.Model): id = models.BigAutoField(primary_key=True) name = models.TextField() email = models.EmailField(unique=True) password_hash = models.TextField() def check_password(self, raw_password): # 对用户输入的原始密码哈希后,与数据库存储值对比 hasher = hashlib.sha256() hasher.update(bytes(raw_password, "UTF-8")) input_hash = hasher.hexdigest() return self.password_hash == input_hash class Session(models.Model): id = models.BigAutoField(primary_key=True) user = models.OneToOneField(User, on_delete=models.CASCADE) token = models.TextField() class Destination(models.Model): id = models.BigAutoField(primary_key=True) name = models.TextField() review = models.TextField() rating = models.PositiveIntegerField() share_publicly = models.BooleanField(default=False) user = models.ForeignKey("User", related_name="destinations", on_delete=models.CASCADE)
2. 修复登录视图逻辑
调整执行顺序:先验证用户身份,再创建关联用户的Session,最后设置Cookie
import hashlib import random import string from django.http import HttpRequest, HttpResponse, Http404, redirect from django.shortcuts import render from .models import User, Session def login(request: HttpRequest): if request.method == "POST": email = request.POST.get('email') raw_password = request.POST.get('password') try: user = User.objects.get(email=email) # 使用修复后的密码验证方法 if user.check_password(raw_password): # 生成32位随机token token = ''.join(random.choice(string.ascii_lowercase) for _ in range(32)) # 创建关联当前用户的Session Session.objects.create(user=user, token=token) # 重定向首页并设置Cookie response = redirect("/") response.set_cookie('token', token) return response else: return HttpResponse("Invalid password") except User.DoesNotExist: return Http404("Invalid email") return render(request, "destination/login.html")
仅显示当前登录用户的目的地
1. 编写获取当前登录用户的工具函数
# 可放在app的utils.py文件中 from .models import Session def get_current_user(request): token = request.COOKIES.get('token') if not token: return None try: session = Session.objects.get(token=token) return session.user except Session.DoesNotExist: return None
2. 在视图中过滤用户专属目的地
from django.shortcuts import render from .models import Destination from .utils import get_current_user def user_destinations(request): current_user = get_current_user(request) if not current_user: return redirect("/login") # 方法1:直接通过外键过滤 destinations = Destination.objects.filter(user=current_user) # 方法2:使用related_name反向查询(更简洁) # destinations = current_user.destinations.all() return render(request, "destination/user_destinations.html", {"destinations": destinations})
内容的提问来源于stack exchange,提问作者Wade Kemmsies
相关产品推荐
相关产品推荐

