微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为 Djoser 中未激活的用户返回适当的错误

如何解决为 Djoser 中未激活的用户返回适当的错误

我将 Django 2.2.14 与 Djoser 2.1.0 的以下配置一起使用,但是当尝试为非活动用户获取 JWT 令牌时,它返回与使用错误密码相同的错误,这使得区分起来很棘手。 我得到 HTTP STATUS 401,详细信息如下

{ "detail": "No active account found with the given credentials }

我的配置Djoser如下图:

 'LOGIN_FIELD': 'email','SEND_CONFIRMATION_EMAIL': True,'PASSWORD_CHANGED_EMAIL_CONFIRMATION': True,'USER_CREATE_PASSWORD_RETYPE': True,'TOKEN_MODEL': None,'SEND_ACTIVATION_EMAIL': True,"logoUT_ON_PASSWORD_CHANGE": False,"PASSWORD_RESET_SHOW_EMAIL_NOT_FOUND": True,"USERNAME_RESET_SHOW_EMAIL_NOT_FOUND": True,'PASSWORD_RESET_CONFIRM_URL': 'account/password/reset/confirm/{uid}/{token}','USERNAME_RESET_CONFIRM_URL': 'account/username/reset/  /{uid}/{token}','ACTIVATION_URL': 'account/activate/{uid}/{token}',

我也在使用 AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']

解决方法

经过一番挖掘,发现 Djoser 使用 simple-jwt 模块生成其 JWT 令牌,因此,错误消息来自该模块。

在一些为 simple-jwt 做出贡献的人的帮助下,我能够修改如下所示的代码,使端点检查用户是否处于非活动状态并发送适当的错误。

# custom_serializers.py
from django.contrib.auth.models import update_last_login
from rest_framework_simplejwt.serializers import TokenObtainSerializer
from rest_framework_simplejwt.exceptions import AuthenticationFailed
from rest_framework import status
from rest_framework_simplejwt.settings import api_settings
from rest_framework_simplejwt.tokens import RefreshToken


class InActiveUser(AuthenticationFailed):
    status_code = status.HTTP_406_NOT_ACCEPTABLE
    default_detail = "User is not active,please confirm your email"
    default_code = 'user_is_inactive'


# noinspection PyAbstractClass
class CustomTokenObtainPairSerializer(TokenObtainSerializer):

    @classmethod
    def get_token(cls,user):
        return RefreshToken.for_user(user)

    def validate(self,attrs):
        data = super().validate(attrs)
        if not self.user.is_active:
            raise InActiveUser()

        refresh = self.get_token(self.user)

        data['refresh'] = str(refresh)
        data['access'] = str(refresh.access_token)

        if api_settings.UPDATE_LAST_LOGIN:
            update_last_login(None,self.user)

        return data

# custom_authentication.py
def custom_user_authentication_rule(user):
    """
    Override the default user authentication rule for Simple JWT Token to return true if there is a user and let
    serializer check whether user is active or not to return an appropriate error.
Add 'USER_AUTHENTICATION_RULE': 'path_to_custom_user_authentication_rule' to simplejwt settings to override the default.
    :param user: user to be authenticated
    :return: True if user is not None
    """

    return True if user is not None else False

# views.py
from .custom_serializer import CustomTokenObtainPairSerializer,InActiveUser
from rest_framework.response import Response
from rest_framework_simplejwt.exceptions import AuthenticationFailed,InvalidToken,TokenError
from rest_framework_simplejwt.views import TokenViewBase

class CustomTokenObtainPairView(TokenViewBase):
    """
    Takes a set of user credentials and returns an access and refresh JSON web
    token pair to prove the authentication of those credentials.

    Returns HTTP 406 when user is inactive and HTTP 401 when login credentials are invalid.
    """
    serializer_class = CustomTokenObtainPairSerializer

    def post(self,request,*args,**kwargs):
        serializer = self.get_serializer(data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
        except AuthenticationFailed:
            raise InActiveUser()
        except TokenError:
            raise InvalidToken()

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

# urls.py
 path('api/token/',CustomTokenObtainPairView.as_view(),name='token_obtain_pair'),path('api/token/refresh/',TokenRefreshView.as_view(),name='token_refresh'),path('api/token/verify/',TokenVerifyView.as_view(),name='token_verify'),

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。