init
This commit is contained in:
0
backend/apps/authentication/__init__.py
Normal file
0
backend/apps/authentication/__init__.py
Normal file
3
backend/apps/authentication/admin.py
Normal file
3
backend/apps/authentication/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
backend/apps/authentication/apps.py
Normal file
6
backend/apps/authentication/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AuthenticationConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'apps.authentication'
|
||||
0
backend/apps/authentication/migrations/__init__.py
Normal file
0
backend/apps/authentication/migrations/__init__.py
Normal file
3
backend/apps/authentication/models.py
Normal file
3
backend/apps/authentication/models.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
backend/apps/authentication/tests.py
Normal file
3
backend/apps/authentication/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
11
backend/apps/authentication/urls.py
Normal file
11
backend/apps/authentication/urls.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# authentication/urls.py - Authentication URL patterns
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = 'authentication'
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', views.login_view, name='login'),
|
||||
path('logout/', views.logout_view, name='logout'),
|
||||
path('check/', views.check_auth_view, name='check'),
|
||||
]
|
||||
127
backend/apps/authentication/views.py
Normal file
127
backend/apps/authentication/views.py
Normal file
@@ -0,0 +1,127 @@
|
||||
# authentication/views.py - Authentication API views
|
||||
import hashlib
|
||||
from django.contrib.auth import login, logout
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.sessions.models import Session
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.response import Response
|
||||
from django_ratelimit.decorators import ratelimit
|
||||
from apps.core.models import SystemSettings
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_client_ip(request):
|
||||
"""Extract client IP address from request"""
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(',')[0].strip()
|
||||
else:
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
return ip
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@permission_classes([AllowAny])
|
||||
@csrf_exempt
|
||||
@ratelimit(key='ip', rate='10/min', method='POST', block=True)
|
||||
def login_view(request):
|
||||
"""
|
||||
Authenticate user with system password.
|
||||
Rate limited to prevent brute force attacks.
|
||||
"""
|
||||
try:
|
||||
password = request.data.get('password')
|
||||
|
||||
if not password:
|
||||
return Response(
|
||||
{'error': 'Password is required'},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
settings_obj = SystemSettings.get_settings()
|
||||
|
||||
if settings_obj.check_password(password):
|
||||
# Create or get session
|
||||
if not request.session.session_key:
|
||||
request.session.create()
|
||||
|
||||
# Store authentication in session
|
||||
request.session['authenticated'] = True
|
||||
request.session['auth_timestamp'] = timezone.now().isoformat()
|
||||
request.session['client_ip'] = get_client_ip(request)
|
||||
request.session.save()
|
||||
|
||||
logger.info(f"Successful login from IP: {get_client_ip(request)}")
|
||||
|
||||
return Response({
|
||||
'success': True,
|
||||
'message': 'Authentication successful',
|
||||
'session_key': request.session.session_key
|
||||
})
|
||||
else:
|
||||
logger.warning(f"Failed login attempt from IP: {get_client_ip(request)}")
|
||||
return Response(
|
||||
{'error': 'Invalid password'},
|
||||
status=status.HTTP_401_UNAUTHORIZED
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Login failed: {e}")
|
||||
return Response(
|
||||
{'error': 'Authentication failed'},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@permission_classes([AllowAny])
|
||||
@csrf_exempt
|
||||
def logout_view(request):
|
||||
"""Clear user session and log out"""
|
||||
try:
|
||||
request.session.flush()
|
||||
logger.info("User logged out successfully")
|
||||
return Response({
|
||||
'success': True,
|
||||
'message': 'Logged out successfully'
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Logout failed: {e}")
|
||||
return Response(
|
||||
{'error': 'Logout failed'},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
)
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([AllowAny])
|
||||
@csrf_exempt
|
||||
def check_auth_view(request):
|
||||
"""Check if user is authenticated"""
|
||||
is_authenticated = request.session.get('authenticated', False)
|
||||
|
||||
if is_authenticated:
|
||||
# Optional: Check session age for additional security
|
||||
auth_timestamp = request.session.get('auth_timestamp')
|
||||
if auth_timestamp:
|
||||
try:
|
||||
auth_time = timezone.datetime.fromisoformat(auth_timestamp)
|
||||
if timezone.now() - auth_time > timedelta(hours=24):
|
||||
request.session.flush()
|
||||
is_authenticated = False
|
||||
except (ValueError, TypeError):
|
||||
request.session.flush()
|
||||
is_authenticated = False
|
||||
|
||||
return Response({
|
||||
'authenticated': is_authenticated,
|
||||
'session_key': request.session.session_key if is_authenticated else None
|
||||
})
|
||||
Reference in New Issue
Block a user