Python 覆盖简单的jwt';s TokenActainPairSerializer以实现2FA

Python 覆盖简单的jwt';s TokenActainPairSerializer以实现2FA,python,django,django-rest-framework,jwt,Python,Django,Django Rest Framework,Jwt,我目前正试图在Django应用程序中实现2FA。我做的第一件事是修改UserSerializer类中的Meta类,以添加两个字段enabled(指示是否为用户启用了2FA)和secret\u key(生成OTP的密钥,当用户启用2FA时,该密钥将共享给用户) 为了尽可能少地修改登录流,我修改了用于生成访问令牌的表单,以包含一个新字段“otp”。用户可以填写或不填写,后端将检查用户是否启用了2FA,如果是,则检查OTP是否正确 如果没有2FA,登录只不过是一个POST请求,其正文{“usernam

我目前正试图在Django应用程序中实现2FA。我做的第一件事是修改
UserSerializer
类中的
Meta
类,以添加两个字段
enabled
(指示是否为用户启用了2FA)和
secret\u key
(生成OTP的密钥,当用户启用2FA时,该密钥将共享给用户)

为了尽可能少地修改登录流,我修改了用于生成访问令牌的表单,以包含一个新字段“otp”。用户可以填写或不填写,后端将检查用户是否启用了2FA,如果是,则检查OTP是否正确

如果没有2FA,登录只不过是一个POST请求,其正文
{“username”:usr,“password”:pwd}
。这已成为一个POST请求,其正文
{“username”:usr,“password”:pwd,“otp”:otp}
。如果用户没有启用2FA,他只需将
opt
字段留空即可

我的
url.py
如下所示:

path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair")

我的想法是覆盖TokenGetPairView以适应新的请求。根据我的发现,我必须更改
validate
方法,但我真的不知道该怎么做。我可能需要获取用户的
enabled
secret\u key
字段的值(基于用户名)来生成OTP(如果相关),并对照
OTP
字段进行检查。问题是,我不知道怎么做,我在简单的jwt实现中有点迷失了方向。

首先,我不会为您的问题提供完整的解决方案,但这可能是一个好的开始

创建自定义的登录视图:

class LoginView(TokenObtainPairView):
    serializer_class = LoginSerializer
class LoginSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        # implement your logic here
        # data = super().validate(attrs)
        return data
实现您自己的序列化程序,该序列化程序继承TokenActainPairSerializer

class LoginView(TokenObtainPairView):
    serializer_class = LoginSerializer
class LoginSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        # implement your logic here
        # data = super().validate(attrs)
        return data
更改URL.py

path("api/token/", LoginView.as_view(), name="token_obtain_pair")
这就是令牌获取序列化程序的外观:

class TokenObtainSerializer(serializers.Serializer):
    username_field = User.USERNAME_FIELD

    default_error_messages = {
        'no_active_account': _('No active account found with the given credentials')
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields[self.username_field] = serializers.CharField()
        self.fields['password'] = PasswordField()

    def validate(self, attrs):
        authenticate_kwargs = {
            self.username_field: attrs[self.username_field],
            'password': attrs['password'],
        }
        try:
            authenticate_kwargs['request'] = self.context['request']
        except KeyError:
            pass

        self.user = authenticate(**authenticate_kwargs)

        if not getattr(login_rule, user_eligible_for_login)(self.user):
            raise exceptions.AuthenticationFailed(
                self.error_messages['no_active_account'],
                'no_active_account',
            )

        return {}
因此,您可以在自己的序列化程序中实现
\uuuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu