簡體   English   中英

如何解決 DRF 簡單 jwt 用戶登錄中的錯誤 401 未授權登錄

[英]How to solve error 401 unauthorized login in DRF simple jwt user login

我正在我的 Django 項目中為 Abstract Base 用戶創建 DRF 身份驗證 API,並且我正在使用簡單的 JWT。 注冊和 email 驗證 API 工作正常,但是當我嘗試使用有效用戶的憑據登錄時,我收到錯誤 401 未授權訪問。

models.py中的自定義用戶 model

class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=255, unique=True,db_index=True)
    email = models.EmailField(max_length=255, unique=True,db_index=True)
    is_verified = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now_add=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELD = ['username']

    objects = UserManager()

    def __str__(self):
        return self.email

    def tokens(self):
        refresh = RefreshToken.for_user(self)
        return{
            'refresh':str(refresh),
            'access': str(refresh.access_token)
        }

這是我的views.py

class RegisterView(generics.GenericAPIView):

    serializer_class = RegisterSerializer
    
    def post(self, request):
        user = request.data
        serializer = self.serializer_class(data=user)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        user_data = serializer.data
        user = User.objects.get(email=user_data['email'])

        token = RefreshToken.for_user(user).access_token

        current_site = get_current_site(request).domain
        relativeLink = reverse('email-verify')

        absurl = 'http://' + current_site + relativeLink + "?token=" + str(token)
        email_body = "Hi " + user.username+ 'Use the link below to verify your email \n' + absurl
        data = {'email_body': email_body,'to_email': user.email,
         'email_subject':'Verify your email'}
        Util.send_email(data)

 
        return Response(user_data, status=status.HTTP_201_CREATED)

class VerifyEmail(views.APIView):
    serializer_class = EmailVerificationSerializer

    token_param_config = openapi.Parameter('token',in_=openapi.IN_QUERY, description='Description', type=openapi.TYPE_STRING)

    @swagger_auto_schema(manual_parameters=[token_param_config])
    def get(self, request):
        token = request.GET.get('token')
        try:
            payload = jwt.decode(token,settings.SECRET_KEY, algorithms=['HS256'])
            user = User.objects.get(id=payload['user_id'])
            if not user.is_verified:
                user.is_verified = True
                user.save()
            return Response({'email': 'Succesfully activated'}, status = status.HTTP_200_OK)

        except jwt.ExpiredSignatureError as identifier:
            return Response({'error': 'Activation Expired'}, status= status.HTTP_400_BAD_REQUEST)
        except jwt.exceptions.DecodeError as identifier:
            return Response({'error': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST)
            
class LoginAPIView(generics.GenericAPIView):
    serializer_class = LoginSerializer
    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)

        return Response(serializer.data, status=status.HTTP_200_OK)

這是我的serializers.py

class RegisterSerializer(serializers.ModelSerializer):
    password = serializers.CharField(
        max_length=68, min_length=8, write_only=True)
  

    class Meta:
        model = User
        fields= ['email', 'username','password']

    def validate(self, attrs):
        email = attrs.get('email', '')
        username = attrs.get('username', '')
  
        if not username.isalnum():
            raise serializers.ValidationError(
                'The username should only contain alphanumeric charachters')
        return attrs

    def create(self, validated_data):
        return User.objects.create_user(**validated_data) 

class EmailVerificationSerializer(serializers.ModelSerializer):
    token = serializers.CharField(max_length= 555)

    class Meta:
        model = User
        fields = ['token']

class LoginSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(max_length=255, min_length=3)
    password = serializers.CharField(max_length=68, min_length=8, write_only=True)
    username = serializers.CharField(max_length=255, min_length=3, read_only = True)
    tokens = serializers.CharField(max_length=68, min_length=8, read_only = True)


    class Meta:
        model = User
        fields = ['email', 'password', 'username', 'tokens']


    def validate(self, attrs):
        email = attrs.get('email', '')
        password = attrs.get('password', '')
  
        user = auth.authenticate(email=email, password=password)

        if not user:
            raise AuthenticationFailed('Invalid Credentials, try again!')
        if not user.is_active:
            raise AuthenticationFailed('Acccount disabled, please contact admin')
        if not user.is_verified:
            raise AuthenticationFailed('Email is not verified')
                
        return {
            'email': user.email,
            'username': user.username,
            'tokens': user.tokens
        }
        
        return super().validate(attrs)

所以引發的錯誤是“無效的憑據”,這意味着用戶的詳細信息不存在,而當我檢查數據庫時用戶實際上就在那里。 在此處輸入圖像描述

任何人,請幫助。

您想要的是從您在 settings.py 中添加的項目范圍的身份驗證檢查中排除您的登錄視圖。

class LoginAPIView(generics.GenericAPIView):
    permission_classes = ()
    authentication_classes = ()
    serializer_class = LoginSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)

        return Response(serializer.data, status=status.HTTP_200_OK)

因此,經過大量的谷歌搜索和頭痛之后,我最終再次閱讀了Simple Jwt 文檔,事實證明,如果用戶不活動,則會出現 401 錯誤。 在我上面的models.py中,默認情況下,我的用戶的is_verifiedis_activeFalse 在用戶驗證他們的電子郵件后, VerifyEmail視圖將is_verified更改為True ,但他們的is_active仍然為False ,因此出現錯誤 401 我的解決方案是在用戶驗證其 email 時添加is_active=True :這是views.py中的VerifyEmail視圖

class VerifyEmail(views.APIView):
    serializer_class = EmailVerificationSerializer

    token_param_config = openapi.Parameter('token',in_=openapi.IN_QUERY, description='Description', type=openapi.TYPE_STRING)

    @swagger_auto_schema(manual_parameters=[token_param_config])
    def get(self, request):
        token = request.GET.get('token')
        try:
            payload = jwt.decode(token,settings.SECRET_KEY, algorithms=['HS256'])
            user = User.objects.get(id=payload['user_id'])
            if not user.is_verified:
                user.is_verified = True
                user.is_active = True           # New
                user.save()
            return Response({'email': 'Succesfully activated'}, status = status.HTTP_200_OK)

        except jwt.ExpiredSignatureError as identifier:
            return Response({'error': 'Activation Expired'}, status= status.HTTP_400_BAD_REQUEST)
        except jwt.exceptions.DecodeError as identifier:
            return Response({'error': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST)

這對我有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM