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

如何解码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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 16:15:51