From 3b8a90c1cbdd16d07da7d045c8bfd2bbe08576aa Mon Sep 17 00:00:00 2001 From: Arnaud Fournier Date: Wed, 4 Feb 2026 11:18:25 +0100 Subject: [PATCH 1/3] chore: setup jwt auth endpoints in django backend --- README.md | 7 +------ backend/README.md | 3 ++- backend/all4trees/settings.py | 5 +++++ backend/all4trees/urls.py | 10 ++-------- backend/requirements.txt | 2 ++ backend/users/urls.py | 15 +++++++++++++++ webapp/package-lock.json | 17 ++++++++++++++++- 7 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 backend/users/urls.py diff --git a/README.md b/README.md index 3c08be0c..4c6e1a1c 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,4 @@ Le Frontend est en ReactJS + Vite, dans le dossier [webapp](./webapp). ## Règles de collaboration : -- Aucun Push ne doit être fait directement sur main. -- Pour travailler sur une évolution du site, il vous faudra d'abord créer une branche et l'associer à une tâche du tableau Kanban. -- Pour plus de clarté et faciliter la collaboration, il serait préférable de nommer vos branches selon le format suivant: -`{votrePseudo}/{tâche}`, par exemple `arnaudfnr/gestion_auth` -- Lorsque votre code est prêt, il faudra créer une Pull Request avec une description claire et concise du code ajouté. -- La Pull Request sera ensuite revue par un autre dev, puis fusionnée avec la branche main une fois que les changements auront été validés. \ No newline at end of file +[Voir le guide de contribution](https://outline.services.dataforgood.fr/doc/onboarding-dev-dzWHb9O90Q) \ No newline at end of file diff --git a/backend/README.md b/backend/README.md index df4b6c0b..be722eee 100644 --- a/backend/README.md +++ b/backend/README.md @@ -7,7 +7,8 @@ Endpoints ------------ - `http://localhost:8000/admin`: interface d'administration par défaut de Django, permettant de gérer les utilisateurs et les groupes. -- `http://localhost:8000/users`: permet de récupérer la liste des utilsiateurs. +- `htpp://localhost:8000/admin/doc` : interface de documentation des applications installées sur Django. +- `http://localhost:8000/users`: permet de récupérer la liste des utilisateurs. - `http://localhost:8000/groups`: permet de récupérer la liste des groupes. Installation diff --git a/backend/all4trees/settings.py b/backend/all4trees/settings.py index cb40f9f3..4f1dfdf5 100644 --- a/backend/all4trees/settings.py +++ b/backend/all4trees/settings.py @@ -32,12 +32,14 @@ INSTALLED_APPS = [ 'django.contrib.admin', + 'django.contrib.admindocs', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', + 'rest_framework_simplejwt', ] MIDDLEWARE = [ @@ -120,4 +122,7 @@ REST_FRAMEWORK = { "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination", "PAGE_SIZE": 10, + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ), } \ No newline at end of file diff --git a/backend/all4trees/urls.py b/backend/all4trees/urls.py index 994c3ef3..2e822d70 100644 --- a/backend/all4trees/urls.py +++ b/backend/all4trees/urls.py @@ -16,17 +16,11 @@ """ from django.contrib import admin from django.urls import include, path -from rest_framework import routers - -from users import views - -router = routers.DefaultRouter() -router.register(r"users", views.UserViewSet) -router.register(r"groups", views.GroupViewSet) urlpatterns = [ + path('admin/doc/', include('django.contrib.admindocs.urls')), path('admin/', admin.site.urls), - path("", include(router.urls)), + path("api/", include('users.urls')), path("api-auth/", include("rest_framework.urls", namespace="rest_framework")), ] diff --git a/backend/requirements.txt b/backend/requirements.txt index 45cffb62..e6674d9e 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,3 +1,5 @@ asgiref==3.8.1 Django==4.2.2 djangorestframework==3.16.0 +djangorestframework_simplejwt==5.5.1 +docutils==0.22 \ No newline at end of file diff --git a/backend/users/urls.py b/backend/users/urls.py new file mode 100644 index 00000000..80ed7bf4 --- /dev/null +++ b/backend/users/urls.py @@ -0,0 +1,15 @@ +from django.urls import path +from rest_framework import routers +from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView +from .views import UserViewSet, GroupViewSet + +router = routers.DefaultRouter() +router.register(r"users", UserViewSet) +router.register(r"groups", GroupViewSet) + +urlpatterns = [ + path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), + path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), +] + +urlpatterns += router.urls \ No newline at end of file diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 8b3aae53..f170363c 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -81,6 +81,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -2937,6 +2938,7 @@ "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2947,6 +2949,7 @@ "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2957,6 +2960,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -3015,6 +3019,7 @@ "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", @@ -3266,6 +3271,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3547,6 +3553,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -3664,6 +3671,7 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", "license": "MIT", + "peer": true, "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -4326,6 +4334,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6251,6 +6260,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -6357,6 +6367,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -6376,6 +6387,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -7075,7 +7087,8 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -7256,6 +7269,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7426,6 +7440,7 @@ "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", From a5783b62d8ba36bcabc9e1b88bd8d436100829a4 Mon Sep 17 00:00:00 2001 From: Arnaud Fournier Date: Wed, 4 Feb 2026 11:48:14 +0100 Subject: [PATCH 2/3] Change permission to view user and group lists --- backend/users/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/users/views.py b/backend/users/views.py index 85fa0af0..f56451de 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -11,7 +11,7 @@ class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all().order_by("-date_joined") serializer_class = UserSerializer - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAdminUser] class GroupViewSet(viewsets.ModelViewSet): @@ -21,4 +21,4 @@ class GroupViewSet(viewsets.ModelViewSet): queryset = Group.objects.all().order_by("name") serializer_class = GroupSerializer - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAdminUser] From 44957209821be202db7f9a67ac2e8f7a3d0fd90a Mon Sep 17 00:00:00 2001 From: Arnaud Fournier Date: Wed, 4 Feb 2026 11:48:26 +0100 Subject: [PATCH 3/3] Update readme --- backend/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/README.md b/backend/README.md index be722eee..1277e690 100644 --- a/backend/README.md +++ b/backend/README.md @@ -8,8 +8,13 @@ Endpoints - `http://localhost:8000/admin`: interface d'administration par défaut de Django, permettant de gérer les utilisateurs et les groupes. - `htpp://localhost:8000/admin/doc` : interface de documentation des applications installées sur Django. -- `http://localhost:8000/users`: permet de récupérer la liste des utilisateurs. -- `http://localhost:8000/groups`: permet de récupérer la liste des groupes. +- `http://localhost:8000/api/users`: permet de récupérer la liste des utilisateurs, nécessite d'être adminisitrateur. +- `http://localhost:8000/api/groups`: permet de récupérer la liste des groupes., nécessite d'être administrateur. +- `http://localhost:8000/token`: permet de créer un token JWT à partir des identifiants de connexion d'un utilisateur. +- `http://localhost:8000/token/refresh`: permet de rafraîchir un token JWT. + +Plus d'infos sur la gestion des tokens: +https://django-rest-framework-simplejwt.readthedocs.io/en/latest/index.html Installation ------------ @@ -30,12 +35,7 @@ pip install -r requirements.txt python manage.py migrate ``` -2. Load data into the mysql database -``` bash -python manage.py loaddata db.json -``` - -3. Create admin user +2. Create admin user ``` bash python manage.py createsuperuser ```