init
This commit is contained in:
@@ -1,9 +1,19 @@
|
||||
|
||||
from django.urls import path, include
|
||||
|
||||
# Ajout du package manquant dans requirements.txt ou installez-le avec:
|
||||
# pip install djangorestframework-simplejwt
|
||||
from rest_framework_simplejwt.views import (
|
||||
TokenObtainPairView,
|
||||
TokenRefreshView,
|
||||
)
|
||||
|
||||
|
||||
from .routers import router
|
||||
|
||||
app_name = "api"
|
||||
urlpatterns = [
|
||||
path("", include(router.urls)),
|
||||
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
||||
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
||||
]
|
||||
|
||||
@@ -2,8 +2,12 @@ import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
from channels.auth import AuthMiddlewareStack
|
||||
from channels.sessions import SessionMiddlewareStack
|
||||
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||
|
||||
from app.channels_middleware import JwtOrSessionAuthMiddleware
|
||||
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app.settings')
|
||||
django_asgi_app = get_asgi_application()
|
||||
|
||||
@@ -12,5 +16,5 @@ from .ws_urls import websocket_urlpatterns
|
||||
|
||||
application = ProtocolTypeRouter({
|
||||
"http": django_asgi_app,
|
||||
"websocket": AuthMiddlewareStack(websocket_urlpatterns)
|
||||
"websocket": SessionMiddlewareStack(JwtOrSessionAuthMiddleware(websocket_urlpatterns))
|
||||
})
|
||||
|
||||
79
app/app/channels_middleware.py
Normal file
79
app/app/channels_middleware.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.db import close_old_connections
|
||||
|
||||
from channels.db import database_sync_to_async
|
||||
from channels.middleware import BaseMiddleware
|
||||
from channels.auth import AuthMiddlewareStack
|
||||
from rest_framework_simplejwt.tokens import UntypedToken
|
||||
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
|
||||
from jwt import decode as jwt_decode
|
||||
from django.conf import settings
|
||||
from urllib.parse import parse_qs
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
@database_sync_to_async
|
||||
def get_user_from_token(token):
|
||||
try:
|
||||
# Vérifier que le token est valide
|
||||
UntypedToken(token)
|
||||
|
||||
# Décoder le token et obtenir l'ID de l'utilisateur
|
||||
decoded_data = jwt_decode(token, settings.SECRET_KEY, algorithms=["HS256"])
|
||||
user_id = decoded_data.get('user_id')
|
||||
|
||||
if user_id:
|
||||
return User.objects.get(id=user_id)
|
||||
return AnonymousUser()
|
||||
except (InvalidToken, TokenError, User.DoesNotExist):
|
||||
return AnonymousUser()
|
||||
|
||||
|
||||
@database_sync_to_async
|
||||
def get_user(scope):
|
||||
if "session" in scope:
|
||||
session = scope["session"]
|
||||
user_id = session.get("_auth_user_id")
|
||||
if user_id:
|
||||
try:
|
||||
return User.objects.get(id=user_id)
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
return AnonymousUser()
|
||||
|
||||
|
||||
class JwtOrSessionAuthMiddleware(BaseMiddleware):
|
||||
async def __call__(self, scope, receive, send):
|
||||
# Fermer les connexions DB obsolètes pour éviter les problèmes
|
||||
close_old_connections()
|
||||
|
||||
# Par défaut, définir un utilisateur anonyme
|
||||
scope['user'] = AnonymousUser()
|
||||
|
||||
# Essayer d'abord l'authentification par session
|
||||
if "session" in scope:
|
||||
scope['user'] = await get_user(scope)
|
||||
if not scope['user'].is_anonymous:
|
||||
return await super().__call__(scope, receive, send)
|
||||
|
||||
# Si l'utilisateur est toujours anonyme, essayer JWT
|
||||
if scope['user'].is_anonymous and 'query_string' in scope:
|
||||
# Extraire token des query parameters
|
||||
query_params = parse_qs(scope['query_string'].decode('utf-8'))
|
||||
token = query_params.get('token', [None])[0]
|
||||
|
||||
# Si aucun token dans les query params, chercher dans les headers
|
||||
if not token and 'headers' in scope:
|
||||
headers = dict(scope['headers'])
|
||||
auth_header = headers.get(b'authorization', b'')
|
||||
if auth_header.startswith(b'Bearer '):
|
||||
token = auth_header.decode('utf-8')[7:]
|
||||
|
||||
# Authentifier avec le token si présent
|
||||
if token:
|
||||
scope['user'] = await get_user_from_token(token)
|
||||
|
||||
return await super().__call__(scope, receive, send)
|
||||
@@ -53,6 +53,7 @@ INSTALLED_APPS = [
|
||||
'corsheaders',
|
||||
'channels',
|
||||
'django_filters',
|
||||
'rest_framework_simplejwt',
|
||||
|
||||
'user',
|
||||
'api',
|
||||
@@ -220,6 +221,7 @@ REST_FRAMEWORK = {
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": [
|
||||
"rest_framework.authentication.SessionAuthentication",
|
||||
"rest_framework.authentication.BasicAuthentication",
|
||||
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
||||
],
|
||||
"DEFAULT_RENDERER_CLASSES": [
|
||||
"rest_framework.renderers.JSONRenderer",
|
||||
@@ -227,6 +229,19 @@ REST_FRAMEWORK = {
|
||||
]
|
||||
}
|
||||
|
||||
SIMPLE_JWT = {
|
||||
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
|
||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
|
||||
'ROTATE_REFRESH_TOKENS': False,
|
||||
'BLACKLIST_AFTER_ROTATION': True,
|
||||
'ALGORITHM': 'HS256',
|
||||
'SIGNING_KEY': SECRET_KEY,
|
||||
'VERIFYING_KEY': None,
|
||||
'AUTH_HEADER_TYPES': ('Bearer',),
|
||||
'USER_ID_FIELD': 'id',
|
||||
'USER_ID_CLAIM': 'user_id',
|
||||
}
|
||||
|
||||
# Torrent related
|
||||
DOWNLOAD_BASE_DIR = Path("/transmission/downloads/complete")
|
||||
NGINX_ACCEL_BASE = "/dl/"
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
django
|
||||
django-vite
|
||||
django-cors-headers
|
||||
|
||||
djangorestframework
|
||||
django-filter
|
||||
|
||||
djangorestframework-simplejwt
|
||||
channels[daphne]
|
||||
channels_redis
|
||||
|
||||
|
||||
Reference in New Issue
Block a user