Django密码过期功能失效,如何设置2分钟密码有效期?
解决Django密码2分钟有效期设置问题
问题分析
你当前的配置和代码存在几个关键问题:
PASSWORD_RESET_TIMEOUT是重置密码链接的有效期,并非用户密码本身的有效期,这个配置和你要实现的功能无关。models.py里的password_expiry用了TimeField,只能存储时间(如14:30:00),无法记录完整日期,没法准确计算密码是否过期;且auto_now_add=True只会在用户创建时设置一次,修改密码时不会更新这个时间。login视图完全没有添加密码过期的检查逻辑,所以即使配置了字段也不会生效。
正确实现步骤
1. 修正models.py字段
把password_expiry改为DateTimeField,去掉auto_now_add=True,后续手动控制更新时机:
from django.db import models from django.contrib.auth.models import User class RegisterUser(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) mobile = models.CharField(max_length=100) # 改为DateTimeField,存储密码创建/修改的完整时间 password_expiry = models.DateTimeField(null=True, blank=True) def __str__(self): return self.user.username
2. 确保密码更新时同步更新有效期
在用户创建、修改密码时,设置/更新password_expiry为当前时间,用信号实现示例:
# 在models.py末尾添加 from django.db.models.signals import post_save from django.dispatch import receiver from django.utils import timezone @receiver(post_save, sender=User) def set_initial_password_expiry(sender, instance, created, **kwargs): # 用户创建时,如果设置了密码,初始化有效期 if created and instance.password: register_user, _ = RegisterUser.objects.get_or_create(user=instance) register_user.password_expiry = timezone.now() register_user.save() @receiver(post_save, sender=User) def update_password_expiry_on_change(sender, instance, **kwargs): # 检测密码是否修改,若修改则更新有效期 if instance.pk: old_user = User.objects.get(pk=instance.pk) if old_user.password != instance.password: register_user, _ = RegisterUser.objects.get_or_create(user=instance) register_user.password_expiry = timezone.now() register_user.save()
3. 修改login视图添加过期检查
在登录验证通过后,检查密码是否超过2分钟有效期,若过期则拒绝登录并引导修改密码:
from django.shortcuts import render, redirect from django.contrib import auth from django.utils import timezone from .models import RegisterUser def login(request): if request.method == 'POST': uname = request.POST['uname'] pwd = request.POST['pwd'] user = authenticate(username=uname, password=pwd) if user is not None: if user.is_active: # 获取用户的密码有效期记录 register_user = RegisterUser.objects.filter(user=user).first() if register_user and register_user.password_expiry: # 计算当前时间与密码过期时间的差值(分钟) time_diff = (timezone.now() - register_user.password_expiry).total_seconds() / 60 if time_diff > 2: # 密码过期,跳转到修改密码页面 return redirect('password_change') # 密码未过期,正常登录 auth.login(request, user) return redirect('home') # 验证失败,返回登录页(可添加错误提示) return render(request, 'login.html', {'error': '用户名/密码错误或密码已过期'}) else: return render(request, 'login.html')
4. (可选)添加密码修改路由
在urls.py中配置Django自带的密码修改视图,让过期用户能修改密码:
from django.contrib.auth import views as auth_views urlpatterns = [ # ... 其他路由 path('password-change/', auth_views.PasswordChangeView.as_view(template_name='password_change.html'), name='password_change'), path('password-change/done/', auth_views.PasswordChangeDoneView.as_view(template_name='password_change_done.html'), name='password_change_done'), ]
关键说明
- 不要使用
PASSWORD_RESET_TIMEOUT控制密码本身的有效期,这个配置仅针对密码重置邮件中的链接有效时长。 - 必须在密码创建/修改时同步更新
password_expiry,否则过期时间永远是用户创建时的时间,逻辑会出错。
内容的提问来源于stack exchange,提问作者Jerin Raju
相关产品推荐
相关产品推荐

