From b6860ecdc508c408d01c22675170e988dc333137 Mon Sep 17 00:00:00 2001 From: RafaUC Date: Thu, 27 Jun 2024 20:11:58 -0600 Subject: [PATCH 1/3] implementando tokens --- cosiap_api/cosiap_api/settings.py | 29 +++++++++++++++++++- cosiap_api/cosiap_api/urls.py | 2 +- cosiap_api/users/urls.py | 4 +++ cosiap_api/users/views.py | 31 ++++++++++++++++++++-- cosiap_frontend/src/users/autenticador.jsx | 7 +++++ 5 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 cosiap_frontend/src/users/autenticador.jsx diff --git a/cosiap_api/cosiap_api/settings.py b/cosiap_api/cosiap_api/settings.py index f08a3c9..85194ee 100644 --- a/cosiap_api/cosiap_api/settings.py +++ b/cosiap_api/cosiap_api/settings.py @@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/5.0/ref/settings/ """ import os +from datetime import timedelta # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -48,7 +49,7 @@ INSTALLED_APPS = [ 'users', ] -MIDDLEWARE = [ +MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', @@ -172,6 +173,32 @@ REST_FRAMEWORK = { 'rest_framework_simplejwt.authentication.JWTAuthentication', ), 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated' + #'rest_framework.permissions.AllowAny' + ], +} + +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True +SESSION_COOKIE_HTTPONLY = True + +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), + 'ROTATE_REFRESH_TOKENS': False, + 'BLACKLIST_AFTER_ROTATION': False, + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': SECRET_KEY, + 'VERIFYING_KEY': None, + 'AUDIENCE': None, + 'ISSUER': None, + 'AUTH_HEADER_TYPES': ('Bearer',), + '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', } SPECTACULAR_SETTINGS = { diff --git a/cosiap_api/cosiap_api/urls.py b/cosiap_api/cosiap_api/urls.py index e4f406e..5bdbd07 100644 --- a/cosiap_api/cosiap_api/urls.py +++ b/cosiap_api/cosiap_api/urls.py @@ -24,7 +24,7 @@ from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, Spec urlpatterns = [ path('admin/', admin.site.urls), - path('',include('users.urls')), + path('api/usuarios/',include('users.urls')), path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), diff --git a/cosiap_api/users/urls.py b/cosiap_api/users/urls.py index 93a2484..6f09047 100644 --- a/cosiap_api/users/urls.py +++ b/cosiap_api/users/urls.py @@ -16,7 +16,11 @@ Including another URLconf from . import views from django.urls import path from django.contrib.auth import views as auth_views +from .views import CustomTokenObtainPairView, CustomTokenRefreshView + app_name = 'users' urlpatterns = [ + path('token/', CustomTokenObtainPairView.as_view(), name='token_obtain_pair'), + path('token/refresh/', CustomTokenRefreshView.as_view(), name='token_refresh'), ] \ No newline at end of file diff --git a/cosiap_api/users/views.py b/cosiap_api/users/views.py index 91ea44a..8a3f93b 100644 --- a/cosiap_api/users/views.py +++ b/cosiap_api/users/views.py @@ -1,3 +1,30 @@ -from django.shortcuts import render +from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView +from rest_framework.response import Response +from rest_framework import status +from django.conf import settings +from datetime import datetime, timedelta -# Create your views here. +class CustomTokenObtainPairView(TokenObtainPairView): + def post(self, request, *args, **kwargs): + response = super().post(request, *args, **kwargs) + if response.status_code == status.HTTP_200_OK: + refresh_token = response.data['refresh'] + response.set_cookie( + key='refresh_token', + value=refresh_token, + httponly=True, + secure=True, + samesite='Strict', # Whether to set the flag restricting cookie leaks on cross-site requests. This can be 'Lax', 'Strict', or None to disable the flag. + expires=datetime.now() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'], + ) + # Eliminar el refresh token de la respuesta JSON + del response.data['refresh'] + return response + +class CustomTokenRefreshView(TokenRefreshView): + def post(self, request, *args, **kwargs): + refresh_token = request.COOKIES.get('refresh_token') + if refresh_token: + request.data['refresh'] = refresh_token + response = super().post(request, *args, **kwargs) + return response \ No newline at end of file diff --git a/cosiap_frontend/src/users/autenticador.jsx b/cosiap_frontend/src/users/autenticador.jsx new file mode 100644 index 0000000..8a62065 --- /dev/null +++ b/cosiap_frontend/src/users/autenticador.jsx @@ -0,0 +1,7 @@ +import { + useEffect, + useLayoutEffect, + useContext, + useEffect, + createContext, +} from 'react'; \ No newline at end of file -- GitLab From 9a0818c05c53c4251d6c8a5a41d9d06d7917b2cd Mon Sep 17 00:00:00 2001 From: RafaUC Date: Fri, 28 Jun 2024 02:17:27 -0600 Subject: [PATCH 2/3] implementado autenticador y funcion de login en el frontend --- cosiap_api/cosiap_api/settings.py | 7 +- cosiap_api/cosiap_api/urls.py | 8 +- cosiap_api/users/views.py | 7 +- cosiap_frontend/Dockerfile | 2 +- cosiap_frontend/entrypoint.sh | 6 +- cosiap_frontend/package-lock.json | 100 +++++++++++++++++++++ cosiap_frontend/package.json | 1 + cosiap_frontend/src/App.jsx | 20 +++-- cosiap_frontend/src/api.js | 44 +++++++++ cosiap_frontend/src/main.jsx | 4 +- cosiap_frontend/src/users/InicioTest.jsx | 21 +++++ cosiap_frontend/src/users/autenticador.jsx | 100 +++++++++++++++++++-- cosiap_frontend/src/users/loginPage.jsx | 55 ++++++++++-- cosiap_frontend/vite.config.js | 12 ++- docker-compose.yaml | 2 +- 15 files changed, 347 insertions(+), 42 deletions(-) create mode 100644 cosiap_frontend/src/api.js create mode 100644 cosiap_frontend/src/users/InicioTest.jsx diff --git a/cosiap_api/cosiap_api/settings.py b/cosiap_api/cosiap_api/settings.py index 85194ee..c8c6413 100644 --- a/cosiap_api/cosiap_api/settings.py +++ b/cosiap_api/cosiap_api/settings.py @@ -209,6 +209,7 @@ SPECTACULAR_SETTINGS = { # OTHER SETTINGS } -#CORS_ALLOWED_ORIGINS = [ -# "http://localhost:5173" -#] +CORS_ALLOW_CREDENTIALS = True +CORS_ALLOWED_ORIGINS = [ + "http://localhost:5173" +] diff --git a/cosiap_api/cosiap_api/urls.py b/cosiap_api/cosiap_api/urls.py index 5bdbd07..47067aa 100644 --- a/cosiap_api/cosiap_api/urls.py +++ b/cosiap_api/cosiap_api/urls.py @@ -16,20 +16,14 @@ Including another URLconf """ from django.contrib import admin from django.urls import path, include -from rest_framework_simplejwt.views import ( - TokenObtainPairView, - TokenRefreshView, -) from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView urlpatterns = [ path('admin/', admin.site.urls), path('api/usuarios/',include('users.urls')), - - path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), - path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # API Doc UI: + path('api/schema/', SpectacularAPIView.as_view(), name='schema'), path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'), path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'), ] \ No newline at end of file diff --git a/cosiap_api/users/views.py b/cosiap_api/users/views.py index 8a3f93b..a9499d3 100644 --- a/cosiap_api/users/views.py +++ b/cosiap_api/users/views.py @@ -24,7 +24,10 @@ class CustomTokenObtainPairView(TokenObtainPairView): class CustomTokenRefreshView(TokenRefreshView): def post(self, request, *args, **kwargs): refresh_token = request.COOKIES.get('refresh_token') - if refresh_token: - request.data['refresh'] = refresh_token + if not refresh_token: + return Response({"detail": "Refresh token is missing."}, status=status.HTTP_400_BAD_REQUEST) + request.data['refresh'] = refresh_token response = super().post(request, *args, **kwargs) + if response.status_code != status.HTTP_200_OK: + response.delete_cookie('refresh_token') return response \ No newline at end of file diff --git a/cosiap_frontend/Dockerfile b/cosiap_frontend/Dockerfile index cd81c8f..0b9adf9 100644 --- a/cosiap_frontend/Dockerfile +++ b/cosiap_frontend/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /app COPY ./package.json . COPY ./package-lock.json . -RUN npm install +#RUN npm install COPY . . diff --git a/cosiap_frontend/entrypoint.sh b/cosiap_frontend/entrypoint.sh index c77204c..7690926 100644 --- a/cosiap_frontend/entrypoint.sh +++ b/cosiap_frontend/entrypoint.sh @@ -1,5 +1,7 @@ #!/bin/sh -npm run dev-exposed & -npx tailwindcss -i ./src/input.css -o ./src/output.css --watch +echo "RUN npm install" +npm install --verbose +npm run dev-exposed & +npx tailwindcss -i ./src/input.css -o ./src/output.css --watch \ No newline at end of file diff --git a/cosiap_frontend/package-lock.json b/cosiap_frontend/package-lock.json index 0f91cef..445cb0a 100644 --- a/cosiap_frontend/package-lock.json +++ b/cosiap_frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "cosiap_frontend", "version": "0.0.0", "dependencies": { + "axios": "^1.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-helmet-async": "^2.0.5", @@ -1359,6 +1360,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -1374,6 +1381,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1526,6 +1544,18 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1683,6 +1713,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2256,6 +2295,26 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -2282,6 +2341,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3190,6 +3263,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3752,6 +3846,12 @@ "react-is": "^16.13.1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/cosiap_frontend/package.json b/cosiap_frontend/package.json index e75ab70..b2f90c0 100644 --- a/cosiap_frontend/package.json +++ b/cosiap_frontend/package.json @@ -11,6 +11,7 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-helmet-async": "^2.0.5", diff --git a/cosiap_frontend/src/App.jsx b/cosiap_frontend/src/App.jsx index 747e3da..8bbb67d 100644 --- a/cosiap_frontend/src/App.jsx +++ b/cosiap_frontend/src/App.jsx @@ -1,8 +1,10 @@ import React, { useEffect, useState } from "react"; import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; -import {LoginPage} from "./users/loginPage" -import {PaginaHead} from "./common/PaginaHead" -import "./App.css" +import {LoginPage} from "./users/loginPage"; +import {PaginaHead} from "./common/PaginaHead"; +import {Autenticador} from "./users/Autenticador"; +import {InicioTest} from "@/users/InicioTest" +import "./App.css"; function App() { return ( @@ -12,10 +14,14 @@ function App() { - - } /> - } /> - + + + } /> + } /> + } /> + + + ); } diff --git a/cosiap_frontend/src/api.js b/cosiap_frontend/src/api.js new file mode 100644 index 0000000..e708b11 --- /dev/null +++ b/cosiap_frontend/src/api.js @@ -0,0 +1,44 @@ +import axios from "axios"; +axios.defaults.withCredentials = true; + +const apiUrl = "http://localhost:8000"; + + +// Configuración de Axios +const api = axios.create({ + baseURL: apiUrl, + timeout: 10000, // Tiempo máximo de espera para las solicitudes (en milisegundos) +}); + +// Interceptor de solicitud +api.interceptors.request.use( + (config) => { + // Aquí puedes manipular la configuración de la solicitud antes de enviarla al servidor + console.log('Solicitud enviada:', config); + // Por ejemplo, agregar encabezados comunes como token de autenticación + // config.headers['Authorization'] = `Bearer ${localStorage.getItem('token')}`; + return config; + }, + (error) => { + // Manejo de errores del interceptor de solicitud + console.log('Error en el interceptor de solicitud:', error); + return Promise.reject(error); + } +); + +// Interceptor de respuesta +api.interceptors.response.use( + (response) => { + // Aquí puedes manipular la respuesta antes de pasarla al código que la llamó + console.log('Respuesta recibida:', response); + return response; + }, + (error) => { + // Manejo de errores del interceptor de respuesta + console.log('Error en el interceptor de respuesta:', error); + return Promise.reject(error); + } +); + +// Exportar la instancia de Axios como tu API principal +export default api; \ No newline at end of file diff --git a/cosiap_frontend/src/main.jsx b/cosiap_frontend/src/main.jsx index 0b3166c..e7f84ab 100644 --- a/cosiap_frontend/src/main.jsx +++ b/cosiap_frontend/src/main.jsx @@ -5,7 +5,7 @@ import './index.css' import './output.css' ReactDOM.createRoot(document.getElementById('root')).render( - + // - , + //, ) diff --git a/cosiap_frontend/src/users/InicioTest.jsx b/cosiap_frontend/src/users/InicioTest.jsx new file mode 100644 index 0000000..3c33620 --- /dev/null +++ b/cosiap_frontend/src/users/InicioTest.jsx @@ -0,0 +1,21 @@ +import { useAutenticacion } from '@/users/Autenticador'; +import {Navigate} from 'react-router-dom'; + +export const InicioTest = () => { + const {token} = useAutenticacion(); + console.log(`INICIOTEST TOKEN: ${token}`) + if (token === null ) { + return ; + } else if (token === undefined) { + return( + <> + ); + }else { + return( + <> + Pagina de inicio + + ); + } + +}; \ No newline at end of file diff --git a/cosiap_frontend/src/users/autenticador.jsx b/cosiap_frontend/src/users/autenticador.jsx index 8a62065..cd9856b 100644 --- a/cosiap_frontend/src/users/autenticador.jsx +++ b/cosiap_frontend/src/users/autenticador.jsx @@ -1,7 +1,93 @@ -import { - useEffect, - useLayoutEffect, - useContext, - useEffect, - createContext, -} from 'react'; \ No newline at end of file +import { + useEffect, + useLayoutEffect, + useContext, + createContext, + useState, +} from "react"; +import api from '@/api' +import PropTypes from 'prop-types'; + +const ContextoAut = createContext(undefined); + +export const useAutenticacion = () => { + const contextoAut = useContext(ContextoAut); + + if (!contextoAut) { + throw new Error( + "useAutenticacion se tiene que usar dentro de un componente autenticador" + ); + } + + return contextoAut; +}; + +export const Autenticador = ({ children }) => { + console.log('INICIALIZANDO AUTENTICADOR') + const [token, setToken] = useState(); + + useEffect(() => { + const buscarUsuario = async () => { + console.log('setear session') + try { + const response = await api.post('api/usuarios/token/refresh/'); + setToken(response.data.access); + } catch { + setToken(null); + } + } + + buscarUsuario(); + }, []); + + useLayoutEffect(() => { + const interceptadorAccess = api.interceptors.request.use((config) => { + console.log(`insertar token en request: ${token}`) + config.headers.Authorization = !config.__retry && token ? `Bearer ${token}` : config.headers.Authorization; + return config; + }); + + return () => { + api.interceptors.request.eject(interceptadorAccess); + }; + + }, [token]); + + useLayoutEffect(() => { + const interceptadorRefresh = api.interceptors.response.use( + (response) => response, async (error) => { + const requestOriginal = error.config; + + console.log('error en la response'); + if (error.response.status === 403 && error.response.data.message === 'Unauthorized') { + try { + const response = await api.post('api/usuarios/token/refresh/'); + setToken(response.data.access); + requestOriginal.headers.Authorization = `Bearer ${response.data.access}`; + requestOriginal.__retry = true; + + return api(requestOriginal); + } catch { + setToken(null); + } + } + + return Promise.reject(error); + }, + ); + + return () => { + api.interceptors.response.eject(interceptadorRefresh); + }; + }); + return ( + + {console.log(token)} + {children} + + ); +}; + +Autenticador.propTypes = { + children: PropTypes.node, +}; \ No newline at end of file diff --git a/cosiap_frontend/src/users/loginPage.jsx b/cosiap_frontend/src/users/loginPage.jsx index c93c30d..c9897ae 100644 --- a/cosiap_frontend/src/users/loginPage.jsx +++ b/cosiap_frontend/src/users/loginPage.jsx @@ -1,8 +1,49 @@ +import { useState } from 'react'; +import api from '@/api'; -export function LoginPage(){ - return ( - <> - Login page - - ); -} \ No newline at end of file +export function LoginPage() { + const [curp, setCurp] = useState(''); + const [password, setPassword] = useState(''); + + const handleSubmit = async (event) => { + event.preventDefault(); + + try { + const response = await api.post('api/usuarios/token/', { curp, password }); + console.log('Respuesta del servidor:', response.data); + // Aquí puedes manejar la respuesta del servidor, por ejemplo, redirigir al usuario a otra página + } catch (error) { + console.error('Error al enviar la solicitud:', error); + // Aquí puedes manejar errores, como mostrar un mensaje al usuario + } + }; + + return ( +
+

Login Page

+
+ +
+ +
+ +
+
+ ); +} diff --git a/cosiap_frontend/vite.config.js b/cosiap_frontend/vite.config.js index fb14d26..8847835 100644 --- a/cosiap_frontend/vite.config.js +++ b/cosiap_frontend/vite.config.js @@ -1,10 +1,16 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react-swc' +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react-swc'; +import path from 'path'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], server: { host: '0.0.0.0' - } + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, }) diff --git a/docker-compose.yaml b/docker-compose.yaml index 5bbd3f8..5020b92 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -44,7 +44,7 @@ services: context: ./cosiap_frontend volumes: - ./cosiap_frontend:/app - - /app/node_modules + #- /app/node_modules environment: - CHOKIDAR_USEPOLLING=true ports: -- GitLab From f7c0158a33d1e023a094ad2c535f47cec265a0f5 Mon Sep 17 00:00:00 2001 From: RafaUC Date: Fri, 28 Jun 2024 14:39:57 -0600 Subject: [PATCH 3/3] implementadas las rutas que necesitan loguin --- cosiap_api/users/views.py | 2 +- cosiap_frontend/docker-compose.yaml | 2 +- cosiap_frontend/src/App.jsx | 15 ++++++---- cosiap_frontend/src/api.js | 3 +- .../src/common/LoginRequiredRoutes.jsx | 16 ++++++++++ cosiap_frontend/src/users/InicioTest.jsx | 30 +++++++------------ 6 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 cosiap_frontend/src/common/LoginRequiredRoutes.jsx diff --git a/cosiap_api/users/views.py b/cosiap_api/users/views.py index a9499d3..3cfe5cd 100644 --- a/cosiap_api/users/views.py +++ b/cosiap_api/users/views.py @@ -21,7 +21,7 @@ class CustomTokenObtainPairView(TokenObtainPairView): del response.data['refresh'] return response -class CustomTokenRefreshView(TokenRefreshView): +class CustomTokenRefreshView(TokenRefreshView): def post(self, request, *args, **kwargs): refresh_token = request.COOKIES.get('refresh_token') if not refresh_token: diff --git a/cosiap_frontend/docker-compose.yaml b/cosiap_frontend/docker-compose.yaml index 7b14af4..ab8a9ff 100644 --- a/cosiap_frontend/docker-compose.yaml +++ b/cosiap_frontend/docker-compose.yaml @@ -8,7 +8,7 @@ services: context: . volumes: - .:/app - - /app/node_modules + #- /app/node_modules environment: - CHOKIDAR_USEPOLLING=true ports: diff --git a/cosiap_frontend/src/App.jsx b/cosiap_frontend/src/App.jsx index 8bbb67d..113ebfb 100644 --- a/cosiap_frontend/src/App.jsx +++ b/cosiap_frontend/src/App.jsx @@ -1,11 +1,13 @@ import React, { useEffect, useState } from "react"; import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; -import {LoginPage} from "./users/loginPage"; import {PaginaHead} from "./common/PaginaHead"; import {Autenticador} from "./users/Autenticador"; -import {InicioTest} from "@/users/InicioTest" +import {LoginRequiredRoutes} from "./common/LoginRequiredRoutes" import "./App.css"; +import {LoginPage} from "./users/loginPage"; +import {InicioTest} from './users/InicioTest'; + function App() { return ( @@ -16,9 +18,12 @@ function App() { - } /> - } /> - } /> + } /> + } /> + {/* Rutas protegidas */} + }> + } /> + diff --git a/cosiap_frontend/src/api.js b/cosiap_frontend/src/api.js index e708b11..8e3f03f 100644 --- a/cosiap_frontend/src/api.js +++ b/cosiap_frontend/src/api.js @@ -6,8 +6,7 @@ const apiUrl = "http://localhost:8000"; // Configuración de Axios const api = axios.create({ - baseURL: apiUrl, - timeout: 10000, // Tiempo máximo de espera para las solicitudes (en milisegundos) + baseURL: apiUrl, }); // Interceptor de solicitud diff --git a/cosiap_frontend/src/common/LoginRequiredRoutes.jsx b/cosiap_frontend/src/common/LoginRequiredRoutes.jsx new file mode 100644 index 0000000..f20b064 --- /dev/null +++ b/cosiap_frontend/src/common/LoginRequiredRoutes.jsx @@ -0,0 +1,16 @@ +import { useAutenticacion } from "@/users/Autenticador"; +import { Navigate, Outlet } from "react-router-dom"; + +export const LoginRequiredRoutes = () => { + const { token } = useAutenticacion(); + + if (token === null) { + return ; + } else if (token === undefined) { + return null; // O un spinner de carga o marcador de posición + } else { + return ; + } +}; + +export default LoginRequiredRoutes; diff --git a/cosiap_frontend/src/users/InicioTest.jsx b/cosiap_frontend/src/users/InicioTest.jsx index 3c33620..9b6e9e1 100644 --- a/cosiap_frontend/src/users/InicioTest.jsx +++ b/cosiap_frontend/src/users/InicioTest.jsx @@ -1,21 +1,11 @@ -import { useAutenticacion } from '@/users/Autenticador'; -import {Navigate} from 'react-router-dom'; - export const InicioTest = () => { - const {token} = useAutenticacion(); - console.log(`INICIOTEST TOKEN: ${token}`) - if (token === null ) { - return ; - } else if (token === undefined) { - return( - <> - ); - }else { - return( - <> - Pagina de inicio - - ); - } - -}; \ No newline at end of file + return ( +
+

Inicio

+

Inicio

+

Inicio

+

Inicio

+
Inicio
+
+ ); +} -- GitLab