Dans le plugin django-rest-framework-simplejwt, username
et password
sont utilisés par défaut. Mais je voulais utiliser email
au lieu de username
. Donc, j'ai fait comme ci-dessous:
Dans le sérialiseur:
class MyTokenObtainPairView(TokenObtainPairView): """ Takes a set of user credentials and returns an access and refresh JSON web token pair to prove the authentication of those credentials. """ serializer_class = MyTokenObtainPairSerializer
En vue:
XXX
Et ça marche !!
Maintenant ma question est, comment puis-je le faire plus efficacement? Quelqu'un peut-il donner une suggestion à ce sujet? Merci d'avance.
4 Réponses :
Cette réponse est destinée aux futurs lecteurs et contient donc des informations supplémentaires.
Afin de simplifier le backend d'authentification, vous devez vous connecter à plusieurs classes. Je suggère de faire l ' option 1 (et éventuellement l' option 3 , une version simplifiée de la vôtre) ci-dessous. Quelques notes avant de lire:
User.objects.filter (email__iexact = ...)
pour faire correspondre les e-mails sans respecter la casse. get_user_model ()
au cas où vous remplaceriez le modèle utilisateur par défaut à l'avenir, c'est vraiment une bouée de sauvetage pour les débutants! Quant aux 3 options:
class EmailModelBackend (ModelBackend)
et remplacez la fonction d'authentification.
authenticate (username =, password =, ** kwarg)
de django.contrib.auth
authenticate (...)
, remplace uniquement l'authentification JWT (si vous la configurez comme telle)
n'est pas obligatoire et cette option est donc moins conseillée). MyTokenObtainPairSerializer
avec l'e-mail comme revendication.
Option 1 (notez que cela autorise également le nom d'utilisateur !!):
SIMPLE_JWT = { 'USER_ID_FIELD': 'id', # model property to attempt claims for 'USER_ID_CLAIM': 'user_id', # actual keyword in token data }
Option 2: fort> Ignoré, laissé au lecteur et non conseillé.
Option 3: Vous semblez avoir couvert cela ci-dessus.
Remarque: vous n'avez pas à définir MyTokenObtainPairView
, vous pouvez utiliser TokenObtainPairView (serializer_class = MyTokenObtainPairSerializer) .as_view ()
dans votre urls.py. Petite simplification qui remplace le sérialiseur de jetons utilisé.
Remarque 2: Vous pouvez spécifier la revendication d'identification et les données ajoutées dans vos paramètres.py (ou fichier de paramètres) pour utiliser également le courrier électronique. Cela obligera votre application frontend à utiliser également l'e-mail pour la réclamation (au lieu de l'adresse par défaut user)
from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend from django.db.models import Q class EmailorUsernameModelBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): UserModel = get_user_model() try: user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username)) except UserModel.DoesNotExist: return None else: if user.check_password(password): return user return None
Cependant, tenez compte des avertissements d'unicité donné par les créateurs:
Par exemple, spécifier un champ "nom d'utilisateur" ou "e-mail" serait un mauvais choix car le nom d'utilisateur ou l'adresse e-mail d'un compte peut changer en fonction de la façon dont la gestion du compte dans un service donné est conçue.
Si vous pouvez garantir l'unicité, vous êtes prêt.
Pourquoi avez-vous copié et collé autant au lieu de sous-classer? Je l'ai fait fonctionner avec:
#urls.py from rest_framework_simplejwt.views import TokenRefreshView from .views import EmailTokenObtainPairView url("token/", EmailTokenObtainPairView.as_view(), name="token_obtain_pair"), url("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
Et
# views.py from rest_framework_simplejwt.views import TokenObtainPairView class EmailTokenObtainPairView(TokenObtainPairView): serializer_class = CustomTokenObtainPairSerializer
Et bien sûr
# serializers.py from rest_framework_simplejwt.serializers import TokenObtainSerializer class EmailTokenObtainSerializer(TokenObtainSerializer): username_field = User.EMAIL_FIELD class CustomTokenObtainPairSerializer(EmailTokenObtainSerializer): @classmethod def get_token(cls, user): return RefreshToken.for_user(user) def validate(self, attrs): data = super().validate(attrs) refresh = self.get_token(self.user) data["refresh"] = str(refresh) data["access"] = str(refresh.access_token) return data
Et en plus de la réponse de @ Mic, n'oubliez pas de définir USERNAME_FIELD = 'email'
et peut être REQUIRED_FIELDS = ['username']
dans le modèle utilisateur. p>
La question fait longtemps mais j'ajoute +1 pour la réponse de @ Mic. Au fait, n'était-il pas suffisant de mettre à jour vers TokenObtainPairSerializer
uniquement comme suit?:
from rest_framework_simplejwt.views import TokenObtainPairView from rest_framework_simplejwt.serializers import ( TokenObtainPairSerializer, User ) class CustomTokenObtainPairSerializer(TokenObtainPairSerializer): username_field = User.EMAIL_FIELD class EmailTokenObtainPairView(TokenObtainPairView): serializer_class = CustomTokenObtainPairSerializer