如何从过期JWT Token中提取payload获取user_id以重发账户激活邮件
解决JWT过期时提取user_id的方案
你可以通过关闭JWT的过期时间校验(保留签名校验,防止伪造token)来从过期的有效token中提取payload内容,以下是两种适配你现有代码的实现方式:
方法1:使用PyJWT原生参数关闭过期校验
在jwt.ExpiredSignatureError捕获块中,重新调用jwt.decode时添加options={"verify_exp": False}参数,仅跳过过期时间校验,仍然验证token签名合法性,就能拿到payload里的user_id,修改后代码如下:
@api_view(['POST']) def ConfirmEmailView(request): try: activation_token = request.data['activation_token'] payload = jwt.decode(activation_token,settings.SECRET_KEY, algorithms=['HS256']) user = User.objects.get(id = payload['user_id']) if user.is_confirmed: return Response('Already verified!', status=status.HTTP_200_OK) user.is_confirmed = True user.save() return Response(status=status.HTTP_202_ACCEPTED) except jwt.ExpiredSignatureError as identifier: # 仅跳过过期时间校验,仍验证签名合法性,防止伪造token payload = jwt.decode( activation_token, settings.SECRET_KEY, algorithms=['HS256'], options={"verify_exp": False} ) user_id = payload['user_id'] # 此处调用你封装的激活邮件发送逻辑,给对应用户重发邮件 # 注意添加发送频率限制,避免被恶意刷接口 return Response("激活链接已过期,新的激活邮件已发送至您的邮箱", status=status.HTTP_403_FORBIDDEN) except Exception as e: print(e) return Response(status=status.HTTP_400_BAD_REQUEST)
方法2:使用djangorestframework-simplejwt内置工具解析(更适配你的token生成逻辑)
因为你生成激活token用的是simplejwt的RefreshToken,也可以直接用simplejwt的内置能力解析,后续如果调整simplejwt的签名算法、密钥等配置不需要额外修改解码参数:
from rest_framework_simplejwt.tokens import RefreshToken from rest_framework_simplejwt.exceptions import TokenError @api_view(['POST']) def ConfirmEmailView(request): try: activation_token = request.data['activation_token'] payload = jwt.decode(activation_token,settings.SECRET_KEY, algorithms=['HS256']) user = User.objects.get(id = payload['user_id']) if user.is_confirmed: return Response('Already verified!', status=status.HTTP_200_OK) user.is_confirmed = True user.save() return Response(status=status.HTTP_202_ACCEPTED) except jwt.ExpiredSignatureError as identifier: try: # verify=False仅跳过过期校验,仍会验证签名合法性 token = RefreshToken(activation_token, verify=False) user_id = token['user_id'] # 此处调用重发邮件逻辑 except TokenError: # token签名无效,属于伪造请求,直接返回错误 return Response("无效的激活链接", status=status.HTTP_400_BAD_REQUEST) return Response("激活链接已过期,新的激活邮件已发送至您的邮箱", status=status.HTTP_403_FORBIDDEN) except Exception as e: print(e) return Response(status=status.HTTP_400_BAD_REQUEST)
注意事项
- 无论用哪种方法,都必须保留签名校验,不能直接拆分JWT字符串裸取payload,否则会被伪造的恶意请求滥用,导致你的邮件发送接口被刷
- 重发激活邮件前建议添加频率限制,比如同一用户1分钟内只能请求重发1次,避免对用户造成邮箱轰炸,也减少你的邮件服务成本
内容的提问来源于stack exchange,提问作者Rares D
相关产品推荐
相关产品推荐

