Files
pagasis/backend/authentication/views.py
T
2025-10-15 23:45:32 -06:00

136 lines
4.4 KiB
Python

from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from django.contrib.auth import login, logout
from django.contrib.auth.models import User
from rest_framework_simplejwt.tokens import RefreshToken
from django_ratelimit.decorators import ratelimit
from django_ratelimit.exceptions import Ratelimited
from .models import UserProfile, Asistente
from .serializers import LoginSerializer, UserSerializer
from .audit import AuditLog
@api_view(['POST'])
@permission_classes([AllowAny])
@ratelimit(key='ip', rate='5/m', method='POST', block=True)
def login_view(request):
"""Login con rate limiting: 5 intentos por minuto por IP"""
serializer = LoginSerializer(data=request.data)
account_number = request.data.get('account_number', 'unknown')
if serializer.is_valid():
user = serializer.validated_data['user']
# Generar tokens JWT
refresh = RefreshToken.for_user(user)
# Log exitoso
AuditLog.log(
category='AUTH',
action='LOGIN_SUCCESS',
message=f'Login exitoso para cuenta {account_number}',
request=request,
user=user,
severity='INFO',
success=True,
status_code=200,
account_number=account_number
)
return Response({
'message': 'Login exitoso',
'user': UserSerializer(user).data,
'tokens': {
'access': str(refresh.access_token),
'refresh': str(refresh)
}
})
# Log fallido
AuditLog.log(
category='AUTH',
action='LOGIN_FAILED',
message=f'Intento de login fallido para cuenta {account_number}',
request=request,
severity='WARNING',
success=False,
status_code=400,
account_number=account_number,
errors=str(serializer.errors)
)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def logout_view(request):
# Log logout
AuditLog.log(
category='AUTH',
action='LOGOUT',
message=f'Logout de usuario {request.user.username}',
request=request,
user=request.user,
severity='INFO',
success=True,
status_code=200
)
logout(request)
return Response({'message': 'Logout exitoso'})
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def user_profile(request):
return Response(UserSerializer(request.user).data)
@api_view(['GET'])
@permission_classes([AllowAny])
@ratelimit(key='ip', rate='30/m', method='GET', block=True)
def check_auth_status(request):
"""Verificar estado de autenticación: 30 consultas por minuto por IP"""
if request.user.is_authenticated:
return Response({
'is_authenticated': True,
'user': UserSerializer(request.user).data
})
return Response({'is_authenticated': False})
@api_view(['POST'])
@permission_classes([AllowAny])
@ratelimit(key='ip', rate='10/m', method='POST', block=True)
def refresh_token(request):
"""Refrescar access token: 10 intentos por minuto por IP"""
from rest_framework_simplejwt.exceptions import TokenError, InvalidToken
from rest_framework_simplejwt.serializers import TokenRefreshSerializer
serializer = TokenRefreshSerializer(data=request.data)
try:
serializer.is_valid(raise_exception=True)
return Response(serializer.validated_data, status=status.HTTP_200_OK)
except TokenError as e:
return Response({'error': 'Token inválido o expirado'}, status=status.HTTP_401_UNAUTHORIZED)
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def verify_token(request):
"""Verificar si el token actual es válido"""
return Response({
'valid': True,
'user': UserSerializer(request.user).data
})
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def get_system_config(request):
"""Obtener la configuración global del sistema"""
from .models import SystemConfiguration
config = SystemConfiguration.get_config()
return Response({
'minimum_attendance_percentage': config.minimum_attendance_percentage,
'minutes_before_event': config.minutes_before_event,
'minutes_after_start': config.minutes_after_start
})