From f4da509044ffa1fac77d9e5613e29a642f1c974a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 03:44:59 +0000 Subject: [PATCH] feat: Update to Django 4+ and add README This commit updates the project to Django 4.2 and related dependencies, including migrating from `djangorestframework-jwt` to `djangorestframework-simplejwt`. Key changes include: - Updated `requirements.txt` with Django>=4.0,<5.0 and compatible versions of DRF, SimpleJWT, and other packages. - Modified Django settings (`settings.py`, `urls.py`) to be compatible with Django 4.x and `rest_framework_simplejwt`. - Updated application code (`registration/models.py`, `registration/views.py`) for Django 4.x and `rest_framework_simplejwt`, including `on_delete` for ForeignKeys and token generation logic. - Ensured migrations run correctly and the tests (though currently empty) execute without errors. - Created a new `README.md` file with comprehensive instructions for project setup, running the development server, and details about available API endpoints. --- README.md | 67 +++++++++++++++++++++++++++++++++++++++--- my_project/settings.py | 41 ++++++++++++++++++++++---- my_project/urls.py | 14 ++++----- registration/models.py | 2 +- registration/views.py | 26 +++++++++++----- requirements.txt | 16 +++++----- 6 files changed, 133 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 54a33ff..a53e526 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,69 @@ -# Implementing Facebook login for DJango web using JWT Authentication Flow +# Django Facebook Registration Project -This repo contains code for the tutorial. Complete tutorial at https://www.trysudo.com/how-to-add-facebook-login-to-django-using-json-web-tokens/ +This project is a Django application that allows users to register and log in using their Facebook account. It also provides an API endpoint to retrieve user details. -Demo at: https://sample-login-codepal.herokuapp.com/ +## Setup Instructions +1. **Clone the repository:** + ```bash + git clone + cd + ``` -## License: MIT +2. **Create and activate a virtual environment:** + ```bash + python3 -m venv venv + source venv/bin/activate # On Windows use `venv\Scripts\activate` + ``` +3. **Install dependencies:** + ```bash + pip install -r requirements.txt + ``` +4. **Set up the database:** + This project uses SQLite by default (as per the settings when no `DATABASE_URL` is provided). + Run migrations to create the necessary database tables: + ```bash + python manage.py migrate + ``` + If you want to use PostgreSQL, set the `DATABASE_URL` environment variable. For example: + `export DATABASE_URL="postgres://user:password@host:port/dbname"` + +5. **Create a superuser (optional):** + To access the Django admin interface, create a superuser: + ```bash + python manage.py createsuperuser + ``` + +## Running the Development Server + +1. **Start the server:** + ```bash + python manage.py runserver + ``` + The application will typically be available at `http://127.0.0.1:8000/`. + +## Available API Endpoints + +The following API endpoints are available: + +* **`POST /api/v1/user/register/facebook`**: + * Registers or logs in a user via their Facebook access token. + * Expects a JSON payload with `{"access_token": "your_facebook_access_token", "userID": "facebook_user_id"}`. (Note: Added `userID` as it's used in `registration/views.py`) + * Returns an access token in the JSON response and sets it in an HTTP-only cookie. + +* **`GET /api/v1/user/get/account`**: + * Retrieves the details of the authenticated user (name, email, Facebook ID). + * Requires a valid JWT access token (typically sent in an HTTP-only cookie after login, or in the `Authorization: Bearer ` header). + +* **`POST /api/token/`**: (Note: Path changed from `/api-token-auth/` during simplejwt migration) + * Obtains JWT tokens (access and refresh). This is the standard endpoint from `rest_framework_simplejwt.views.TokenObtainPairView`. + * Expects a JSON payload with `{"username": "your_username", "password": "your_password"}` for users created via Django admin or other means (not Facebook login). + +## Running Tests + +To run the test suite (currently empty): +```bash +python manage.py test +``` diff --git a/my_project/settings.py b/my_project/settings.py index 0ab5f7a..745508e 100644 --- a/my_project/settings.py +++ b/my_project/settings.py @@ -40,6 +40,7 @@ 'whitenoise.runserver_nostatic', 'django.contrib.staticfiles', 'rest_framework', + 'rest_framework_simplejwt', 'registration' ] @@ -140,18 +141,46 @@ # Rest framework permissions REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', + 'rest_framework_simplejwt.authentication.JWTAuthentication', ), } # JWT Settings # For JWT, define an auth cookie name -JWT_AUTH_COOKIE = 'jwt_auth_token' +# JWT_AUTH_COOKIE = 'jwt_auth_token' # No longer used by simplejwt # Set when token expires. -JWT_EXPIRATION_DELTA = datetime.timedelta(days=60) - -JWT_AUTH = {'JWT_AUTH_COOKIE': JWT_AUTH_COOKIE, - 'JWT_EXPIRATION_DELTA': JWT_EXPIRATION_DELTA +# JWT_EXPIRATION_DELTA = datetime.timedelta(days=60) # Configure SIMPLE_JWT settings instead + +# JWT_AUTH = {'JWT_AUTH_COOKIE': JWT_AUTH_COOKIE, # No longer used by simplejwt +# 'JWT_EXPIRATION_DELTA': JWT_EXPIRATION_DELTA +# } + +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': datetime.timedelta(days=60), + 'REFRESH_TOKEN_LIFETIME': datetime.timedelta(days=1), # Example, adjust as needed + 'ROTATE_REFRESH_TOKENS': False, # Example, adjust as needed + 'BLACKLIST_AFTER_ROTATION': True, # Example, adjust as needed + 'UPDATE_LAST_LOGIN': False, # Example, adjust as needed + + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': SECRET_KEY, + 'VERIFYING_KEY': None, + 'AUDIENCE': None, + 'ISSUER': None, + + 'AUTH_HEADER_TYPES': ('Bearer',), + 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', + 'USER_ID_FIELD': 'id', + 'USER_ID_CLAIM': 'user_id', + + 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), + 'TOKEN_TYPE_CLAIM': 'token_type', + + 'JTI_CLAIM': 'jti', + + 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp', + 'SLIDING_TOKEN_LIFETIME': datetime.timedelta(minutes=5), # Example, adjust as needed + 'SLIDING_TOKEN_REFRESH_LIFETIME': datetime.timedelta(days=1), # Example, adjust as needed } diff --git a/my_project/urls.py b/my_project/urls.py index c6fb221..d65c728 100644 --- a/my_project/urls.py +++ b/my_project/urls.py @@ -13,26 +13,26 @@ 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ -from django.conf.urls import url +from django.urls import re_path from django.contrib import admin from django.views.generic import TemplateView -from rest_framework_jwt.views import obtain_jwt_token +from rest_framework_simplejwt.views import TokenObtainPairView from registration.views import register_user_via_facebook, get_user_details urlpatterns = [ - url(r'^admin/', admin.site.urls), + re_path(r'^admin/', admin.site.urls), - url(r'^api-token-auth/', obtain_jwt_token), + re_path(r'^api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # Url for facebook signup - url(r'^api/v1/user/register/facebook', register_user_via_facebook), + re_path(r'^api/v1/user/register/facebook', register_user_via_facebook), # Url to fetch user details - url(r'^api/v1/user/get/account', get_user_details), + re_path(r'^api/v1/user/get/account', get_user_details), - url(r'^$', TemplateView.as_view(template_name='home.html')), + re_path(r'^$', TemplateView.as_view(template_name='home.html')), ] diff --git a/registration/models.py b/registration/models.py index 7791243..093419e 100644 --- a/registration/models.py +++ b/registration/models.py @@ -7,7 +7,7 @@ class FbAuth(models.Model): """Stores Fb auth details for users who sign in via facebook""" - user = models.OneToOneField(User) + user = models.OneToOneField(User, on_delete=models.CASCADE) facebook_token = models.CharField(verbose_name="Facebook auth token", max_length=600, null=False, blank=False, unique=False) facebook_id = models.CharField(verbose_name="Facebook id", max_length=20, null=False, blank=False, unique=False) last_modified = models.DateTimeField(auto_now=True, null=False, blank=False) diff --git a/registration/views.py b/registration/views.py index bca9507..50b9047 100644 --- a/registration/views.py +++ b/registration/views.py @@ -6,9 +6,9 @@ from rest_framework.decorators import api_view, permission_classes from rest_framework.exceptions import APIException from rest_framework.permissions import IsAuthenticated -from rest_framework_jwt.settings import api_settings +from rest_framework_simplejwt.tokens import RefreshToken +from django.conf import settings # To access SIMPLE_JWT settings -from my_project.settings import JWT_AUTH_COOKIE, JWT_EXPIRATION_DELTA from registration.models import FbAuth @@ -33,13 +33,25 @@ def register_user_via_facebook(request): FbAuth.create_or_update(user, data['userID'], data['accessToken']) # Step 3: Return JWT token in cookie. - - payload = api_settings.JWT_PAYLOAD_HANDLER(user) - token = api_settings.JWT_ENCODE_HANDLER(payload) + refresh = RefreshToken.for_user(user) + access_token = str(refresh.access_token) # Step 4: Set token as cookie - response = JsonResponse({'token': token}, safe=False, status=status.HTTP_200_OK) - response.set_cookie(JWT_AUTH_COOKIE, token, JWT_EXPIRATION_DELTA.total_seconds(), httponly=True) + response = JsonResponse({'token': access_token}, safe=False, status=status.HTTP_200_OK) + + # Use a generic cookie name, can be configured in settings if needed + auth_cookie_name = getattr(settings, 'SIMPLE_JWT', {}).get('AUTH_COOKIE', 'jwt_auth_token') + # Use access token lifetime from settings + access_token_lifetime = getattr(settings, 'SIMPLE_JWT', {}).get('ACCESS_TOKEN_LIFETIME') + + if access_token_lifetime: + response.set_cookie( + auth_cookie_name, + access_token, + max_age=access_token_lifetime.total_seconds(), + httponly=True, + samesite=getattr(settings, 'SIMPLE_JWT', {}).get('AUTH_COOKIE_SAMESITE', 'Lax') # Add SameSite attribute + ) return response diff --git a/requirements.txt b/requirements.txt index d70f04d..4ad6196 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,14 @@ appdirs==1.4.3 dj-database-url==0.4.1 -Django==1.10.4 -djangorestframework==3.6.2 -djangorestframework-jwt==1.10.0 +Django>=4.0,<5.0 +djangorestframework>=3.12,<3.15 +djangorestframework-simplejwt>=5.0,<5.4 facebook-sdk==2.0.0 gunicorn==19.6.0 packaging==16.8 -psycopg2==2.6.2 -PyJWT==1.4.2 +psycopg2-binary>=2.8,<2.10 +PyJWT>=2.0,<2.9 pyparsing==2.2.0 -requests==2.13.0 -six==1.10.0 -whitenoise==3.2 +requests>=2.25.0,<2.32.0 +six>=1.15,<1.17 +whitenoise>=6.0,<6.7