如何解码Django密码重置Token以获取其创建时间?
从Django密码重置Token提取创建时间并设置24小时过期
一、先搞懂Token的结构
Django自带的PasswordResetTokenGenerator生成的Token是{timestamp}-{hash}的格式:
- 前面的
timestamp是生成Token时的时间标识(父类默认是从2001-01-01到生成日的天数,Django 4.1+也可能用秒级时间戳,取决于你使用的版本) - 后面的
hash是基于用户ID、timestamp等字段生成的哈希值,用来验证Token合法性
二、提取Token的创建时间
直接拆分Token字符串就能拿到timestamp,再转成具体时间即可:
方式1:在视图里直接处理
在reset_password_confirm视图中添加解析逻辑:
def reset_password_confirm(request, uidb64, token): # 拆分Token获取timestamp部分 try: timestamp_str, _ = token.split('-', 1) timestamp = int(timestamp_str) except ValueError: # Token格式无效 messages.error(request, "无效的重置链接") return redirect('core:reset_password') # 原有获取用户的逻辑 try: uid = force_text(urlsafe_base64_decode(uidb64)) user = User.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, User.DoesNotExist): user = None # 将timestamp转换为具体时间(按父类默认的天数规则) if user: from datetime import datetime, timedelta # 父类默认起始日期为2001-01-01 start_date = datetime(2001, 1, 1) token_created_time = start_date + timedelta(days=timestamp) # 检查是否超过24小时 if (datetime.now() - token_created_time).total_seconds() > 86400: messages.error(request, "重置链接已过期,请重新申请") return redirect('core:reset_password') # 原有Token验证和表单处理逻辑 if user is not None and account_activation_token.check_token(user, token): form = ResetPasswordConfirmationForm(request.POST or None) if form.is_valid(): password = form.cleaned_data.get('password1') user.set_password(password) user.save() login(request,user) messages.success(request,'Password changed!') return redirect('consumer:consumer_home') context = { 'form':form, } return render(request,'core/password_reset_confirmation.html',context)
方式2:给Token生成类添加解析方法
修改tokens.py,给生成器添加提取时间的方法,提升复用性:
from django.contrib.auth.tokens import PasswordResetTokenGenerator import six from datetime import datetime, timedelta class AccountActivationTokenGenerator(PasswordResetTokenGenerator): def _make_hash_value(self, user, timestamp): return ( six.text_type(user.pk) + six.text_type(timestamp) ) def get_token_created_time(self, token): """解析Token,返回创建时间的datetime对象""" try: timestamp_str, _ = token.split('-', 1) timestamp = int(timestamp_str) # 按父类规则转换为具体时间 start_date = datetime(2001, 1, 1) return start_date + timedelta(days=timestamp) except ValueError: return None account_activation_token = AccountActivationTokenGenerator()
之后在视图中调用该方法:
def reset_password_confirm(request, uidb64, token): token_created_time = account_activation_token.get_token_created_time(token) if not token_created_time: messages.error(request, "无效的重置链接") return redirect('core:reset_password') # 检查是否超过24小时 from datetime import datetime if (datetime.now() - token_created_time).total_seconds() > 86400: messages.error(request, "重置链接已过期,请重新申请") return redirect('core:reset_password') # 原有获取用户、验证Token的逻辑...
三、更省心的过期设置:用Django内置配置
其实不用手动解析时间,Django自带Token过期配置,直接在settings.py中添加一行即可:
- Django 3.2+版本:
PASSWORD_RESET_TIMEOUT = 86400 # 24小时,单位为秒
- 更早版本:
PASSWORD_RESET_TIMEOUT_DAYS = 1 # 1天
这样check_token方法会自动验证Token是否过期,无需自己编写时间判断逻辑,省心高效。
注意:如果你重写了_make_hash_value,不要破坏父类的过期验证逻辑,父类的check_token会自动对比timestamp与当前时间的差值是否超过配置的有效期。
内容的提问来源于stack exchange,提问作者Agustin Gonzalez Ribas
相关产品推荐
相关产品推荐

