重写simplejwt的TokenOccessPairSerializer以实现2FA

2024-04-19 18:46:11 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

如果没有2FA,登录只是一个带有body{"username": usr, "password": pwd}的POST请求。这已成为具有body{"username": usr, "password": pwd, "otp": otp}的POST请求。如果用户没有启用2FA,他只需将opt字段留空即可

我的urls.py看起来像这样:

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

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


Tags: djangokey用户tokensecretusrpwdusername
1条回答
网友
1楼 · 发布于 2024-04-19 18:46:11

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

创建自定义的登录视图:

class LoginView(TokenObtainPairView):
    serializer_class = LoginSerializer

实现您自己的序列化程序,该序列化程序继承TokenActainPairSerializer

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 {}

因此,您可以在自己的序列化程序中实现__init___,并添加otp字段,并在validate方法中实现所需的逻辑(您可以在此处访问self.user并检查他是否启用了2FA

相关问题 更多 >