2017-09-30 4 views
1

J'utilise all-auth/django-rest-auth pour Authorization. Lorsque l'utilisateur change son nom d'utilisateur, Django (Django REST Framework) change de jeton utilisateur, ce qui permet à l'utilisateur de se déconnecter de l'application; Je définis l'application pour la déconnexion si le jeton de son utilisateur n'est pas valide.Comment empêcher JWT Django (all-auth) de changer de jeton lorsque son nom d'utilisateur est mis à jour?

Ce que je veux faire est que même si l'utilisateur change le nom d'utilisateur, l'email, ou n'importe quel champ dans User, il garde le jeton.

Voici 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), 
} 

... 

Merci!

Répondre

1

Suggestion:

1) Faire le nom d'utilisateur comme un objet de hachage (UUID) et créer un nouveau champ appelé username_custom, (changer votre login et le registre des vues)

2) Préparer votre mode comme: USERNAME_FIELD = 'username' il est donc le nom d'utilisateur par défaut dans Django

3) ne jamais mettre à jour sur le terrain par défaut nom d'utilisateur et votre jeton ne changera jamais.

Exemple

1) paquet utilisation pour le modèle utilisateur: https://github.com/jcugat/django-custom-user

2) par exemple Modèle

Modèle

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!') 

Vous pouvez voir qu'il ya nouveau champ username_custom.

Maintenant, reste api créer un utilisateur.

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) 

sérialiseur

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 

Vous devez preprare méthode UPDATE pour vérifier champ e-mail unique de sorte que vous ne recevez pas 2 email dans votre DB, ou username_custom tout ce que vous voulez être l'autorisation.

API Login

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) 
+0

Je pense que votre suggestion est très bonne approche ... Comment pouvons-nous fixons USERNAME_FIELD = 'nom d'utilisateur' ?? Pourriez-vous avoir un exemple de code ou un tutoriel? –

+0

Oui, je vais le faire pour vous. – marin

+0

MERCI BEAUCOUP !! –