From 6ce5bab31e15aa2b51d8de2d6f5cb95e0f690dd7 Mon Sep 17 00:00:00 2001 From: fi_van Date: Thu, 22 Feb 2024 16:42:17 +0300 Subject: [PATCH] jwt auth --- backend/cfehome/cfehome/settings.py | 14 ++- backend/cfehome/cfehome/test_settings.py | 20 ++++- backend/cfehome/users/urls.py | 18 +++- js_client/client.js | 107 +++++++++++++++++++++++ js_client/index.html | 26 ++++++ requirements/base.txt | 3 +- 6 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 js_client/client.js create mode 100644 js_client/index.html diff --git a/backend/cfehome/cfehome/settings.py b/backend/cfehome/cfehome/settings.py index 6399eef..c9c7c3b 100644 --- a/backend/cfehome/cfehome/settings.py +++ b/backend/cfehome/cfehome/settings.py @@ -32,6 +32,8 @@ 'algoliasearch_django', 'rest_framework', 'rest_framework.authtoken', + 'rest_framework_simplejwt', + 'corsheaders', 'products.apps.ProductsConfig', 'users.apps.UsersConfig', 'search.apps.SearchConfig', @@ -40,6 +42,7 @@ MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -116,8 +119,7 @@ REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.SessionAuthentication', - 'rest_framework.authentication.TokenAuthentication', + 'rest_framework_simplejwt.authentication.JWTAuthentication', ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticatedOrReadOnly', @@ -131,3 +133,11 @@ 'APPLICATION_ID': os.getenv('ALGOLIA_APPLICATION_ID', 'app_id'), 'API_KEY': os.getenv('ALGOLIA_API_KEY', 'api_key'), } + +CORS_ALLOWED_ORIGINS = [] +if DEBUG: + CORS_ALLOWED_ORIGINS = [ + 'http://localhost:8111', + 'https://localhost:8111', + ] +CORS_URLS_REGEX = r"^/api/.*$" diff --git a/backend/cfehome/cfehome/test_settings.py b/backend/cfehome/cfehome/test_settings.py index 4787e5a..f7c67b6 100644 --- a/backend/cfehome/cfehome/test_settings.py +++ b/backend/cfehome/cfehome/test_settings.py @@ -1,3 +1,4 @@ +import os import pathlib @@ -18,12 +19,15 @@ 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', + 'rest_framework_simplejwt', + 'corsheaders', 'products.apps.ProductsConfig', 'users.apps.UsersConfig', 'search.apps.SearchConfig', ] MIDDLEWARE = [ + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -98,8 +102,7 @@ REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.SessionAuthentication', - 'rest_framework.authentication.TokenAuthentication', + 'rest_framework_simplejwt.authentication.JWTAuthentication', ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticatedOrReadOnly', @@ -108,3 +111,16 @@ 'LimitOffsetPagination', 'PAGE_SIZE': 10, } + +ALGOLIA = { + 'APPLICATION_ID': os.getenv('ALGOLIA_APPLICATION_ID', 'app_id'), + 'API_KEY': os.getenv('ALGOLIA_API_KEY', 'api_key'), +} + +CORS_ALLOWED_ORIGINS = [] +if DEBUG: + CORS_ALLOWED_ORIGINS = [ + 'http://localhost:8111', + 'https://localhost:8111', + ] +CORS_URLS_REGEX = r"^/api/.*$" diff --git a/backend/cfehome/users/urls.py b/backend/cfehome/users/urls.py index 9c4ac9f..ca850d7 100644 --- a/backend/cfehome/users/urls.py +++ b/backend/cfehome/users/urls.py @@ -1,4 +1,4 @@ -import rest_framework.authtoken.views +import rest_framework_simplejwt.views import django.urls @@ -7,8 +7,18 @@ urlpatterns = [ django.urls.path( - 'login/', - rest_framework.authtoken.views.obtain_auth_token, - name='login', + 'token/', + rest_framework_simplejwt.views.TokenObtainPairView.as_view(), + name='token_obtain', + ), + django.urls.path( + 'token/refresh/', + rest_framework_simplejwt.views.TokenRefreshView.as_view(), + name='token_refresh', + ), + django.urls.path( + 'token/verify/', + rest_framework_simplejwt.views.TokenVerifyView.as_view(), + name='token_verify', ), ] diff --git a/js_client/client.js b/js_client/client.js new file mode 100644 index 0000000..6944090 --- /dev/null +++ b/js_client/client.js @@ -0,0 +1,107 @@ +const loginForm = document.getElementById('login-form') +const contentContainer = document.getElementById('content-container') +const searchForm = document.getElementById('search-form') +const baseEndpoint = 'http://localhost:8000/api' +if (loginForm) { + loginForm.addEventListener('submit', handleLogin) +} +if (searchForm){ + searchForm.addEventListener('submit', getProductList) +} +console.log(searchForm) + +function handleLogin(event) { + event.preventDefault() + const loginEndpoint = `${baseEndpoint}/auth/token/` + let loginFormData = new FormData(loginForm) + let loginObjectData = Object.fromEntries(loginFormData) + const options = { + method: 'POST', + headers: { + 'content-type': 'application/json' + }, + body: JSON.stringify(loginObjectData) + } + fetch(loginEndpoint, options).then(response=>{ + return response.json() + }).then(authData => { + handleAuthData(authData, getProductList) + }) +} + +function handleAuthData(authData, callback){ + localStorage.setItem('access', authData.access) + localStorage.setItem('refresh', authData.refresh) + if (callback){ + callback() + } +} + +function isTokenValid(jsonData) { + if (jsonData.code && jsonData.code === 'token_not_valid'){ + alert('Войдите в аккаунт снова') + return false + } return true +} + +function validateJWTToken(){ + const endpoint = `${baseEndpoint}/auth/token/verify/` + const options = { + method: 'POST', + headers: { + 'content-type': 'application/json' + }, + body: JSON.stringify({ + token: localStorage.getItem('access') + }) + } + fetch(endpoint, options) + .then(response=>response.json()) + .then(x => { + isTokenValid(x) + }) +} + +function getFetchOptions(method, body){ + return { + method: method === null ? 'GET': method, + headers: { + 'content-type': 'application/json', + 'Authorization': `Bearer ${localStorage.getItem('access')}` + }, + body: body === null ? null: body + } +} + +function getProductList(event){ + let endpoint = `${baseEndpoint}/products/` + if (event){ + event.preventDefault() + let searchFormData = new FormData(searchForm) + let searchData = Object.fromEntries(searchFormData) + searchParams = new URLSearchParams(searchData) + endpoint = `${baseEndpoint}/products/?${searchParams}` + } + const options = { + method: 'GET', + headers: { + 'content-type': 'application/json', + } + } + console.log(endpoint) + fetch(endpoint, options) + .then(response=>{ + return response.json() + }) + .then(data=>{ + if (isTokenValid(data)) { + writeInContentContainer(data) + } + }) +} + +function writeInContentContainer(data) { + if (contentContainer) { + contentContainer.innerHTML = '
' + JSON.stringify(data, null, 4) + '
' + } +} diff --git a/js_client/index.html b/js_client/index.html new file mode 100644 index 0000000..ec05b9a --- /dev/null +++ b/js_client/index.html @@ -0,0 +1,26 @@ + + + + + + + +
+ + + +
+ +
+ + + +
+ +
+ +
+ + + + \ No newline at end of file diff --git a/requirements/base.txt b/requirements/base.txt index 4a0004d..56cbeec 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -3,4 +3,5 @@ django-cors-headers==4.3.1 djangorestframework==3.14.0 python-dotenv==1.0.1 django_debug_toolbar==4.2.0 -algoliasearch-django==3.0.0 \ No newline at end of file +algoliasearch-django==3.0.0 +djangorestframework-simplejwt==5.3.1 \ No newline at end of file