mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
chore: ajustement JWT
This commit is contained in:
@ -2,12 +2,13 @@ from django.urls import path, re_path
|
||||
|
||||
from . import views
|
||||
import Auth.views
|
||||
from Auth.views import ProfileSimpleView, ProfileView, SessionView, LoginView, SubscribeView, NewPasswordView, ResetPasswordView
|
||||
from Auth.views import ProfileSimpleView, ProfileView, SessionView, LoginView, RefreshJWTView, SubscribeView, NewPasswordView, ResetPasswordView
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r'^csrf$', Auth.views.csrf, name='csrf'),
|
||||
|
||||
re_path(r'^login$', LoginView.as_view(), name="login"),
|
||||
re_path(r'^refreshJWT$', RefreshJWTView.as_view(), name="refresh_jwt"),
|
||||
re_path(r'^subscribe$', SubscribeView.as_view(), name='subscribe'),
|
||||
re_path(r'^newPassword$', NewPasswordView.as_view(), name='newPassword'),
|
||||
re_path(r'^resetPassword/(?P<code>[a-zA-Z]+)$', ResetPasswordView.as_view(), name='resetPassword'),
|
||||
|
||||
@ -13,8 +13,9 @@ from rest_framework import status
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_yasg import openapi
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
import jwt
|
||||
from jwt.exceptions import ExpiredSignatureError, InvalidTokenError
|
||||
import json
|
||||
|
||||
from . import validator
|
||||
@ -26,11 +27,13 @@ from Subscriptions.models import RegistrationForm
|
||||
from Subscriptions.signals import clear_cache
|
||||
import Subscriptions.mailManager as mailer
|
||||
import Subscriptions.util as util
|
||||
|
||||
import logging
|
||||
from N3wtSchool import bdd, error
|
||||
|
||||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||||
|
||||
logger = logging.getLogger("AuthViews")
|
||||
|
||||
|
||||
@swagger_auto_schema(
|
||||
method='get',
|
||||
@ -162,13 +165,17 @@ class LoginView(APIView):
|
||||
),
|
||||
responses={
|
||||
200: openapi.Response('Connexion réussie', schema=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
'token': openapi.Schema(type=openapi.TYPE_STRING),
|
||||
'refresh': openapi.Schema(type=openapi.TYPE_STRING)
|
||||
}
|
||||
)),
|
||||
400: openapi.Response('Connexion échouée', schema=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
'errorFields': openapi.Schema(type=openapi.TYPE_OBJECT),
|
||||
'errorMessage': openapi.Schema(type=openapi.TYPE_STRING),
|
||||
'profil': openapi.Schema(type=openapi.TYPE_INTEGER),
|
||||
'droit': openapi.Schema(type=openapi.TYPE_INTEGER),
|
||||
'id': openapi.Schema(type=openapi.TYPE_INTEGER),
|
||||
'errorMessage': openapi.Schema(type=openapi.TYPE_STRING)
|
||||
}
|
||||
))
|
||||
}
|
||||
@ -179,6 +186,7 @@ class LoginView(APIView):
|
||||
retour = error.returnMessage[error.WRONG_ID]
|
||||
validationOk, errorFields = validatorAuthentication.validate()
|
||||
user = None
|
||||
|
||||
if validationOk:
|
||||
user = authenticate(
|
||||
email=data.get('email'),
|
||||
@ -191,6 +199,31 @@ class LoginView(APIView):
|
||||
user.save()
|
||||
clear_cache()
|
||||
retour = ''
|
||||
# Générer le JWT avec la bonne syntaxe datetime
|
||||
access_payload = {
|
||||
'user_id': user.id,
|
||||
'email': user.email,
|
||||
'droit': user.droit,
|
||||
'type': 'access',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
}
|
||||
|
||||
access_token = jwt.encode(access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||
# Générer le Refresh Token (exp: 7 jours)
|
||||
refresh_payload = {
|
||||
'user_id': user.id,
|
||||
'type': 'refresh',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
}
|
||||
refresh_token = jwt.encode(refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||
|
||||
return JsonResponse({
|
||||
'token': access_token,
|
||||
'refresh': refresh_token
|
||||
}, safe=False)
|
||||
|
||||
else:
|
||||
retour = error.returnMessage[error.PROFIL_INACTIVE]
|
||||
else:
|
||||
@ -199,10 +232,101 @@ class LoginView(APIView):
|
||||
return JsonResponse({
|
||||
'errorFields': errorFields,
|
||||
'errorMessage': retour,
|
||||
'profil': user.id if user else -1,
|
||||
'droit': user.droit if user else -1,
|
||||
'id': user.id if user else -1,
|
||||
}, safe=False)
|
||||
}, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class RefreshJWTView(APIView):
|
||||
@swagger_auto_schema(
|
||||
operation_description="Rafraîchir le token d'accès",
|
||||
request_body=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
required=['refresh'],
|
||||
properties={
|
||||
'refresh': openapi.Schema(type=openapi.TYPE_STRING)
|
||||
}
|
||||
),
|
||||
responses={
|
||||
200: openapi.Response('Token rafraîchi avec succès', schema=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
'token': openapi.Schema(type=openapi.TYPE_STRING),
|
||||
'refresh': openapi.Schema(type=openapi.TYPE_STRING),
|
||||
}
|
||||
)),
|
||||
400: openapi.Response('Échec du rafraîchissement', schema=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
'errorMessage': openapi.Schema(type=openapi.TYPE_STRING)
|
||||
}
|
||||
))
|
||||
}
|
||||
)
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
def post(self, request):
|
||||
data = JSONParser().parse(request)
|
||||
refresh_token = data.get("refresh")
|
||||
logger.info(f"Token reçu: {refresh_token[:20]}...") # Ne pas logger le token complet pour la sécurité
|
||||
|
||||
if not refresh_token:
|
||||
return JsonResponse({'errorMessage': 'Refresh token manquant'}, status=400)
|
||||
|
||||
try:
|
||||
# Décoder le Refresh Token
|
||||
logger.info("Tentative de décodage du token")
|
||||
logger.info(f"Algorithme utilisé: {settings.SIMPLE_JWT['ALGORITHM']}")
|
||||
|
||||
# Vérifier le format du token avant décodage
|
||||
token_parts = refresh_token.split('.')
|
||||
if len(token_parts) != 3:
|
||||
logger.error("Format de token invalide - pas 3 parties")
|
||||
return JsonResponse({'errorMessage': 'Format de token invalide'}, status=400)
|
||||
|
||||
payload = jwt.decode(
|
||||
refresh_token,
|
||||
settings.SIMPLE_JWT['SIGNING_KEY'],
|
||||
algorithms=[settings.SIMPLE_JWT['ALGORITHM']] # Noter le passage en liste
|
||||
)
|
||||
|
||||
logger.info(f"Token décodé avec succès. Type: {payload.get('type')}")
|
||||
# Vérifier s'il s'agit bien d'un Refresh Token
|
||||
if payload.get('type') != 'refresh':
|
||||
return JsonResponse({'errorMessage': 'Token invalide'}, status=400)
|
||||
|
||||
# Récupérer les informations utilisateur
|
||||
user = Profile.objects.get(id=payload['user_id'])
|
||||
|
||||
# Générer un nouveau Access Token avec les informations complètes
|
||||
new_access_payload = {
|
||||
'user_id': user.id,
|
||||
'email': user.email,
|
||||
'droit': user.droit,
|
||||
'type': 'access',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
}
|
||||
|
||||
new_access_token = jwt.encode(new_access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||
|
||||
new_refresh_payload = {
|
||||
'user_id': user.id,
|
||||
'type': 'refresh',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
}
|
||||
new_refresh_token = jwt.encode(new_refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||
|
||||
return JsonResponse({'token': new_access_token, 'refresh': new_refresh_token}, status=200)
|
||||
|
||||
except ExpiredSignatureError as e:
|
||||
logger.error(f"Token expiré: {str(e)}")
|
||||
return JsonResponse({'errorMessage': 'Refresh token expiré'}, status=400)
|
||||
except InvalidTokenError as e:
|
||||
logger.error(f"Token invalide: {str(e)}")
|
||||
return JsonResponse({'errorMessage': f'Token invalide: {str(e)}'}, status=400)
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur inattendue: {str(e)}")
|
||||
return JsonResponse({'errorMessage': f'Erreur inattendue: {str(e)}'}, status=400)
|
||||
|
||||
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
|
||||
Reference in New Issue
Block a user