如何防止JWT Django(all-auth)在更新用户名时更改令牌?

时间:2017-09-30 10:52:22

标签: django django-rest-framework

我使用all-auth / django-rest-auth进行授权。当用户更改他/她的用户名时,Django(Django REST框架)会更改用户的令牌,这会使用户从应用程序注销;如果用户的令牌无效,我会将应用设置为退出。

我想要做的是即使用户更改User中的用户名,电子邮件或任何字段,它也会保留令牌。

这是settings.py

REST_USE_JWT = True
AUTHENTICATION_BACKENDS = (
    # Needed to login by username in Django admin, regardless of `allauth`
    'django.contrib.auth.backends.ModelBackend',

    # `allauth` specific authentication methods, such as login by e-mail
    'allauth.account.auth_backends.AuthenticationBackend',

    # Facebook OAuth2
    'social_core.backends.facebook.FacebookAppOAuth2',
    'social_core.backends.facebook.FacebookOAuth2',

    # django-rest-framework-social-oauth2
    'rest_framework_social_oauth2.backends.DjangoOAuth2',
)
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=30),
}

...

谢谢!

1 个答案:

答案 0 :(得分:1)

建议:

1)将用户名设置为某个哈希对象(uuid)并创建名为 username_custom 的新字段, (更改您的登录和注册视图)

2)准备你的模式: USERNAME_FIELD = 'username'所以它是Django中的默认用户名

3)永远不要更新默认字段用户名,您的令牌永远不会更改。

实施例

1)使用包用于用户模型:https://github.com/jcugat/django-custom-user

2)模型示例

模型

class UserModel(AbstractEmailUser):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)

    username = models.CharField(max_length=255, db_index=True, unique=True)
    email = models.EmailField(unique=False, db_index=True)

    username_custom = models.CharField(max_length=255, db_index=True, unique=True)

    USERNAME_FIELD = 'username'

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        self.first_name = self.first_name.capitalize()
        self.last_name = self.last_name.capitalize()
        self.full_name = '{} {}'.format(self.first_name.capitalize(), self.last_name.capitalize())
        super(UserModel, self).save(force_insert, force_update)

    def clean(self):
        if UserModel.objects.filter(email=self.email, username_custom=self.username_custom).exists():
            raise ValidationError('User already exists!')

您可以看到有新字段 username_custom

现在休息api创建用户。

class UserRegister(APIView):
    permission_classes = (AllowAny,)
    authentication_classes = ()

    def post(self, request):
        data = request.data

        # or you can check username_custom
        if UserModel.objects.filter(email=data['email']).exists():
            return Response(data={'success': False, 'msg': 'User with email already exists.'},
                            status=status.HTTP_403_FORBIDDEN)

        data['username'] = '%s' % uuid.uuid4()

        serializer = UserRegisterSerializer(data=data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()

            token_data = UserModel.objects.get(email=serializer.data['email'])
            payload = jwt_payload_handler(token_data)
            token = jwt_encode_handler(payload)

            return Response(data={'success': True, 'user': serializer.data,
                                  'token': token_prefix + token}, status=status.HTTP_201_CREATED)


        return Response(data={'success': False, 'msg': serializer.errors},
                        status=status.HTTP_400_BAD_REQUEST)

串行

class UserRegisterSerializer(serializers.ModelSerializer):
    username = serializers.UUIDField()

    class Meta:
        model = UserModel
        fields = ('password', 'email', 'user_type', 'username', 'first_name', 'last_name', 'username_custom',)

    def create(self, validated_data):
        user = UserModel.objects.create_user(**validated_data)

        return user

您必须预先制作UPDATE方法以检查唯一的电子邮件字段,这样您就不会在您的数据库中收到2封电子邮件,也不会在您想要授权的情况下收到username_custom。

登录API

class UserLoginView(APIView):
    permission_classes = (AllowAny,)

    def get(self, request, email, password):

        # or you can check username_custom
        if not UserModel.objects.filter(email=email.lower()).exists():
            return Response(data={'success': False, 'msg': 'Email or password wrong!'},
                            status=status.HTTP_404_NOT_FOUND)

        qv = UserModel.objects.get(email=email.lower())
        user = authenticate(username=qv.username, password=password)

        if user:
            if user.is_active:
                token_data = UserModel.objects.get(id=user.id)
                payload = jwt_payload_handler(token_data)
                token = jwt_encode_handler(payload)

                return Response(data={'success': True,
                                  'token': token_prefix + token}, status=status.HTTP_200_OK)

        return Response(data={'success': False, 'msg': 'Email or password wrong!'},
                            status=status.HTTP_400_BAD_REQUEST)