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

重置PIN时Session未保存邮箱与重置码问题排查

PIN重置功能Session丢失问题排查与修复

问题现状

  • 验证重置码(reset_code)通过后,调用SetNewPinView接口时无法从Session中获取之前保存的reset_code和email,返回错误:

{
"error": "Reset code and email not found in session."
}

  • 需求:Postman测试SetNewPin接口时仅传入new_pin和confirm_new_pin两个字段

相关代码

VerifyResetCodeView

class VerifyResetCodeView(APIView):
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        serializer = VerifyResetCodeSerializer(data=request.data)
        if serializer.is_valid():
            reset_code = serializer.validated_data.get('reset_code')

            try:
                pin_reset = PinResetCode.objects.get(reset_code=reset_code)
            except PinResetCode.DoesNotExist:
                return Response({'error': 'Invalid reset code.'}, status=status.HTTP_400_BAD_REQUEST)
            
            if pin_reset.is_expired():
                return Response({'error': 'Reset code expired.'}, status=status.HTTP_400_BAD_REQUEST)

            # Store reset code and email in the session
            request.session['reset_code'] = reset_code
            request.session['email'] = pin_reset.email
            request.session.save()  # Explicitly save the session

            # Debugging statements
            print(f"Storing - Reset Code: {reset_code}, Email: {pin_reset.email}")
            print(f"Stored Session Data - Reset Code: {request.session.get('reset_code')}, Email: {request.session.get('email')}")

            return Response({'message': 'Reset code is Verified. You can now set your new PIN.'}, status=status.HTTP_200_OK)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

SetNewPinView

class SetNewPinView(APIView):
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        serializer = SetNewPinSerializer(data=request.data)
        if serializer.is_valid():
            new_pin = serializer.validated_data.get('new_pin')
            confirm_new_pin = serializer.validated_data.get('confirm_new_pin')

            # Retrieve reset code and email from session
            reset_code = request.session.get('reset_code')
            email = request.session.get('email')

            # Debugging information
            print(f"Session data - Reset Code: {reset_code}, Email: {email}")

            # Ensure reset code and email are present
            if not reset_code or not email:
                return Response({'error': 'Reset code and email not found in session.'}, status=status.HTTP_400_BAD_REQUEST)
            
            # Check if new PINs match
            if new_pin != confirm_new_pin:
                return Response({'error': 'New PIN and confirm new PIN do not match.'}, status=status.HTTP_400_BAD_REQUEST)
            
            try:
                pin_reset = PinResetCode.objects.get(email=email, reset_code=reset_code)
            except PinResetCode.DoesNotExist:
                return Response({'error': 'Invalid reset code.'}, status=status.HTTP_400_BAD_REQUEST)
            
            if pin_reset.is_expired():
                return Response({'error': 'Reset code expired.'}, status=status.HTTP_400_BAD_REQUEST)
            
            user = get_object_or_404(Employee, email=email)
            user.set_password(new_pin)
            user.save()

            pin_reset.delete()

            # Clear session data
            request.session.pop('reset_code', None)
            request.session.pop('email', None)

            return Response({'message': 'PIN reset successful.'}, status=status.HTTP_200_OK)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

测试结果

Postman调用SetNewPinView返回:

{
    "error": "Reset code and email not found in session."
}

修复方案

1. 解决Postman会话保持问题

Postman默认不会自动维护会话Cookie,需手动处理:

  • 调用VerifyResetCode接口后,从响应的Set-Cookie头中复制sessionid的值
  • 在SetNewPin接口的请求头中添加Cookie: sessionid=xxx(替换xxx为实际值)
  • 或在Postman设置中开启Automatically send cookies(Settings → General → Automatically send cookies)

2. 检查Django Session配置

确认settings.py中的Session相关配置:

  • SESSION_ENGINE:确保为django.contrib.sessions.backends.db或其他有效引擎
  • SESSION_COOKIE_SECURE:如果设为True,必须用HTTPS请求,否则Cookie不会被客户端保存
  • SESSION_COOKIE_HTTPONLY:设为True不影响Postman传Cookie,但前端JS无法读取

3. 改用Token替代Session(推荐API场景)

Session更适合Web页面,API场景推荐用一次性Token:

  • 在VerifyResetCodeView验证通过后,生成包含reset_code和email的加密Token(如JWT)
  • SetNewPinView接收Token并解析,无需依赖Session,示例:
    # 安装djangorestframework-simplejwt
    from rest_framework_simplejwt.tokens import RefreshToken
    
    # VerifyResetCodeView返回Token
    def post(self, request):
        # ... 原有验证逻辑 ...
        token = RefreshToken()
        token['reset_code'] = reset_code
        token['email'] = pin_reset.email
        return Response({
            'message': 'Reset code verified',
            'access_token': str(token.access_token)
        })
    
    # SetNewPinView验证Token
    from rest_framework_simplejwt.authentication import JWTAuthentication
    
    class SetNewPinView(APIView):
        authentication_classes = [JWTAuthentication]
        permission_classes = [permissions.AllowAny]
    
        def post(self, request):
            reset_code = request.auth.get('reset_code')
            email = request.auth.get('email')
            # ... 后续逻辑 ...
    

4. 确保Serializer仅校验指定字段

修改SetNewPinSerializer,只保留new_pin和confirm_new_pin:

class SetNewPinSerializer(serializers.Serializer):
    new_pin = serializers.CharField(required=True, min_length=4, max_length=8)
    confirm_new_pin = serializers.CharField(required=True, min_length=4, max_length=8)

    def validate(self, attrs):
        if attrs['new_pin'] != attrs['confirm_new_pin']:
            raise serializers.ValidationError("New PIN and confirm PIN do not match")
        return attrs

内容的提问来源于stack exchange,提问作者Sajjad Jagi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 13:27:14