jerkjs 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -6
- package/docs/EXTENSION_MANUAL.md +955 -0
- package/docs/FIREWALL_MANUAL.md +416 -0
- package/docs/HOOKS_REFERENCE_IMPROVED.md +596 -0
- package/docs/MANUAL_API_SDK.md +536 -0
- package/docs/MARIADB_TOKENS_IMPLEMENTATION.md +110 -0
- package/docs/MIDDLEWARE_MANUAL.md +518 -0
- package/docs/OAUTH2_GOOGLE_MANUAL.md +405 -0
- package/docs/frontend-and-sessions.md +6 -6
- package/examples/advanced/controllers/productController.js +64 -0
- package/examples/advanced/controllers/userController.js +85 -0
- package/examples/advanced/routes.json +51 -0
- package/examples/advanced_example.js +93 -0
- package/examples/basic/controllers/userController.js +85 -0
- package/examples/basic_example.js +72 -0
- package/examples/mvc_example/app.js +138 -0
- package/examples/mvc_example/views/home/index.html +26 -0
- package/examples/mvc_example/views/home/simple.html +3 -0
- package/examples/mvc_example/views/layout.html +23 -0
- package/examples/mvc_example/views/test.html +3 -0
- package/examples/mvc_example/views/user/invalid.html +6 -0
- package/examples/mvc_example/views/user/list.html +36 -0
- package/examples/mvc_example/views/user/notfound.html +6 -0
- package/examples/mvc_example/views/user/profile.html +11 -0
- package/examples/mvc_routes_example/app.js +34 -0
- package/examples/mvc_routes_example/controllers/mainController.js +27 -0
- package/examples/mvc_routes_example/controllers/productController.js +47 -0
- package/examples/mvc_routes_example/controllers/userController.js +76 -0
- package/examples/mvc_routes_example/routes.json +30 -0
- package/examples/mvc_routes_example/views/layout.html +31 -0
- package/examples/mvc_routes_example/views/main/index.html +11 -0
- package/examples/mvc_routes_example/views/product/catalog.html +24 -0
- package/examples/mvc_routes_example/views/user/invalid.html +6 -0
- package/examples/mvc_routes_example/views/user/list.html +40 -0
- package/examples/mvc_routes_example/views/user/notfound.html +6 -0
- package/examples/mvc_routes_example/views/user/profile.html +18 -0
- package/examples/mvc_welcome/README.md +34 -0
- package/examples/mvc_welcome/app.js +50 -0
- package/examples/mvc_welcome/controllers/welcomeController.js +41 -0
- package/examples/mvc_welcome/package.json +26 -0
- package/examples/mvc_welcome/views/home/welcome.html +82 -0
- package/examples/v2/README.md +72 -0
- package/examples/v2/app.js +74 -0
- package/examples/v2/app_fixed.js +74 -0
- package/examples/v2/controllers/authController.js +64 -0
- package/examples/v2/controllers/mainController.js +24 -0
- package/examples/v2/controllers/protectedController.js +12 -0
- package/examples/v2/controllers/userController.js +16 -0
- package/examples/v2/package.json +27 -0
- package/examples/v2/routes.json +30 -0
- package/examples/v2/test_api.sh +47 -0
- package/examples/v2/tokens_example.sqlite +0 -0
- package/examples/v2.1_firewall_demo/README.md +113 -0
- package/examples/v2.1_firewall_demo/app.js +182 -0
- package/examples/v2.1_firewall_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/README.md +85 -0
- package/examples/v2.1_hooks_demo/app.js +101 -0
- package/examples/v2.1_hooks_demo/controllers/hooksController.js +29 -0
- package/examples/v2.1_hooks_demo/controllers/mainController.js +18 -0
- package/examples/v2.1_hooks_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/routes.json +16 -0
- package/examples/v2.1_openapi_demo/README.md +82 -0
- package/examples/v2.1_openapi_demo/app.js +296 -0
- package/examples/v2.1_openapi_demo/package.json +26 -0
- package/examples/v2_cors/README.md +82 -0
- package/examples/v2_cors/app.js +108 -0
- package/examples/v2_cors/package.json +23 -0
- package/examples/v2_json_auth/README.md +83 -0
- package/examples/v2_json_auth/app.js +72 -0
- package/examples/v2_json_auth/controllers/authController.js +67 -0
- package/examples/v2_json_auth/controllers/mainController.js +16 -0
- package/examples/v2_json_auth/controllers/protectedController.js +12 -0
- package/examples/v2_json_auth/controllers/tokenController.js +28 -0
- package/examples/v2_json_auth/controllers/userController.js +15 -0
- package/examples/v2_json_auth/package.json +26 -0
- package/examples/v2_json_auth/routes.json +37 -0
- package/examples/v2_json_auth/tokens.json +20 -0
- package/examples/v2_mariadb_auth/README.md +94 -0
- package/examples/v2_mariadb_auth/app.js +81 -0
- package/examples/v2_mariadb_auth/controllers/authController.js +95 -0
- package/examples/v2_mariadb_auth/controllers/mainController.js +31 -0
- package/examples/v2_mariadb_auth/controllers/protectedController.js +12 -0
- package/examples/v2_mariadb_auth/controllers/userController.js +17 -0
- package/examples/v2_mariadb_auth/package.json +27 -0
- package/examples/v2_mariadb_auth/routes.json +37 -0
- package/examples/v2_no_auth/README.md +75 -0
- package/examples/v2_no_auth/app.js +72 -0
- package/examples/v2_no_auth/controllers/healthController.js +14 -0
- package/examples/v2_no_auth/controllers/mainController.js +19 -0
- package/examples/v2_no_auth/controllers/productController.js +31 -0
- package/examples/v2_no_auth/controllers/publicController.js +16 -0
- package/examples/v2_no_auth/package.json +22 -0
- package/examples/v2_no_auth/routes.json +37 -0
- package/examples/v2_oauth/README.md +70 -0
- package/examples/v2_oauth/app.js +90 -0
- package/examples/v2_oauth/controllers/mainController.js +45 -0
- package/examples/v2_oauth/controllers/oauthController.js +247 -0
- package/examples/v2_oauth/controllers/protectedController.js +13 -0
- package/examples/v2_oauth/controllers/userController.js +17 -0
- package/examples/v2_oauth/package.json +26 -0
- package/examples/v2_oauth/routes.json +44 -0
- package/examples/v2_openapi/README.md +77 -0
- package/examples/v2_openapi/app.js +222 -0
- package/examples/v2_openapi/controllers/authController.js +52 -0
- package/examples/v2_openapi/controllers/mainController.js +26 -0
- package/examples/v2_openapi/controllers/productController.js +17 -0
- package/examples/v2_openapi/controllers/userController.js +27 -0
- package/examples/v2_openapi/package.json +26 -0
- package/examples/v2_openapi/routes.json +37 -0
- package/index.js +11 -3
- package/lib/core/handler.js +1 -1
- package/lib/core/hooks.js +1 -1
- package/lib/core/router.js +1 -1
- package/lib/core/server.js +1 -1
- package/lib/loader/controllerLoader.js +1 -1
- package/lib/loader/routeLoader.js +1 -1
- package/lib/middleware/auditLogger.js +1 -1
- package/lib/middleware/authenticator.js +1 -1
- package/lib/middleware/compressor.js +1 -1
- package/lib/middleware/cors.js +1 -1
- package/lib/middleware/firewall.js +1 -1
- package/lib/middleware/rateLimiter.js +1 -1
- package/lib/middleware/session.js +1 -1
- package/lib/middleware/validator.js +1 -1
- package/lib/mvc/controllerBase.js +207 -0
- package/lib/mvc/viewEngine.js +752 -0
- package/lib/utils/configParser.js +1 -1
- package/lib/utils/logger.js +1 -1
- package/lib/utils/openapiGenerator.js +1 -1
- package/lib/utils/tokenManager.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
# Manual para Implementar OAuth 2.0 con Google usando el Framework API SDK
|
|
2
|
+
|
|
3
|
+
## Índice
|
|
4
|
+
1. [Introducción](#introducción)
|
|
5
|
+
2. [Requisitos Previos](#requisitos-previos)
|
|
6
|
+
3. [Configuración en Google Cloud Console](#configuración-en-google-cloud-console)
|
|
7
|
+
4. [Configuración del Framework API SDK](#configuración-del-framework-api-sdk)
|
|
8
|
+
5. [Implementación del Flujo OAuth 2.0](#implementación-del-flujo-oauth-20)
|
|
9
|
+
6. [Manejo de Tokens](#manejo-de-tokens)
|
|
10
|
+
7. [Protección de Endpoints](#protección-de-endpoints)
|
|
11
|
+
8. [Consideraciones de Seguridad](#consideraciones-de-seguridad)
|
|
12
|
+
9. [Depuración y Troubleshooting](#depuración-y-troubleshooting)
|
|
13
|
+
|
|
14
|
+
## Introducción
|
|
15
|
+
|
|
16
|
+
OAuth 2.0 es un protocolo de autorización que permite a aplicaciones de terceros obtener acceso limitado a cuentas de usuario de un servicio web. En este manual, aprenderás cómo implementar OAuth 2.0 con Google usando el Framework API SDK.
|
|
17
|
+
|
|
18
|
+
## Requisitos Previos
|
|
19
|
+
|
|
20
|
+
- Cuenta de Google
|
|
21
|
+
- Acceso a Google Cloud Console
|
|
22
|
+
- Node.js instalado
|
|
23
|
+
- Framework API SDK instalado
|
|
24
|
+
- Conocimientos básicos de JavaScript y APIs REST
|
|
25
|
+
|
|
26
|
+
## Configuración en Google Cloud Console
|
|
27
|
+
|
|
28
|
+
### Paso 1: Crear un proyecto en Google Cloud Console
|
|
29
|
+
|
|
30
|
+
1. Accede a [Google Cloud Console](https://console.cloud.google.com/)
|
|
31
|
+
2. Haz clic en "Seleccionar un proyecto" o "Nuevo proyecto"
|
|
32
|
+
3. Ingresa un nombre para tu proyecto
|
|
33
|
+
4. Haz clic en "Crear"
|
|
34
|
+
|
|
35
|
+
### Paso 2: Habilitar Google+ API (o las APIs que necesites)
|
|
36
|
+
|
|
37
|
+
1. En el panel lateral izquierdo, haz clic en "APIs y servicios" > "Biblioteca"
|
|
38
|
+
2. Busca "Google+ API" o las APIs que planeas usar (como People API)
|
|
39
|
+
3. Haz clic en "Habilitar"
|
|
40
|
+
|
|
41
|
+
### Paso 3: Crear credenciales OAuth 2.0
|
|
42
|
+
|
|
43
|
+
1. En el panel lateral izquierdo, haz clic en "APIs y servicios" > "Credenciales"
|
|
44
|
+
2. Haz clic en "Crear credenciales" > "ID de cliente OAuth 2.0"
|
|
45
|
+
3. Si aún no has configurado el consentimiento OAuth, haz clic en "Configurar pantalla de consentimiento OAuth"
|
|
46
|
+
4. Completa la información de la pantalla de consentimiento:
|
|
47
|
+
- Tipo de usuario: Público o Interno (según tu necesidad)
|
|
48
|
+
- Ingresa un nombre de aplicación
|
|
49
|
+
- Agrega direcciones de correo electrónico de desarrolladores
|
|
50
|
+
- Ingresa un dominio de aplicación (si aplica)
|
|
51
|
+
5. Guarda la configuración de consentimiento
|
|
52
|
+
|
|
53
|
+
### Paso 4: Configurar las credenciales
|
|
54
|
+
|
|
55
|
+
1. De vuelta en la página de credenciales, haz clic en "Crear credenciales" > "ID de cliente OAuth 2.0"
|
|
56
|
+
2. Selecciona "Aplicación web" como tipo de aplicación
|
|
57
|
+
3. Ingresa un nombre para las credenciales
|
|
58
|
+
4. En "URI de redirección autorizados", agrega las siguientes URLs:
|
|
59
|
+
- `http://localhost:8093/auth/callback` (ajusta el puerto según tu configuración)
|
|
60
|
+
- `http://localhost:3000/auth/callback` (si usas otro puerto)
|
|
61
|
+
- Cualquier otra URL de callback que vayas a usar
|
|
62
|
+
5. Haz clic en "Crear"
|
|
63
|
+
6. Guarda el "ID de cliente" y el "Secreto de cliente" que se mostrarán
|
|
64
|
+
|
|
65
|
+
## Configuración del Framework API SDK
|
|
66
|
+
|
|
67
|
+
### Paso 1: Instalar el Framework API SDK
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install apisdk
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Paso 2: Configurar variables de entorno
|
|
74
|
+
|
|
75
|
+
Crea un archivo `.env` en la raíz de tu proyecto:
|
|
76
|
+
|
|
77
|
+
```env
|
|
78
|
+
OAUTH_CLIENT_ID=tu_client_id_aqui
|
|
79
|
+
OAUTH_CLIENT_SECRET=tu_client_secret_aqui
|
|
80
|
+
OAUTH_CALLBACK_URL=http://localhost:8093/auth/callback
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Paso 3: Importar los componentes necesarios
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
const {
|
|
87
|
+
APIServer,
|
|
88
|
+
Authenticator,
|
|
89
|
+
RouteLoader,
|
|
90
|
+
Logger,
|
|
91
|
+
TokenManager
|
|
92
|
+
} = require('apisdk');
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Implementación del Flujo OAuth 2.0
|
|
96
|
+
|
|
97
|
+
### Paso 1: Configurar el servidor y autenticador
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
const server = new APIServer({
|
|
101
|
+
port: 8093,
|
|
102
|
+
host: 'localhost'
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const authenticator = new Authenticator({ logger });
|
|
106
|
+
|
|
107
|
+
// Registrar la estrategia OAuth2
|
|
108
|
+
authenticator.use('google-oauth', authenticator.oauth2Strategy({
|
|
109
|
+
clientId: process.env.OAUTH_CLIENT_ID,
|
|
110
|
+
clientSecret: process.env.OAUTH_CLIENT_SECRET,
|
|
111
|
+
callbackURL: process.env.OAUTH_CALLBACK_URL,
|
|
112
|
+
authorizationURL: 'https://accounts.google.com/o/oauth2/v2/auth',
|
|
113
|
+
tokenURL: 'https://oauth2.googleapis.com/token'
|
|
114
|
+
}));
|
|
115
|
+
|
|
116
|
+
// Agregar autenticador al servidor
|
|
117
|
+
server.authenticator = authenticator;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Paso 2: Crear el endpoint para iniciar OAuth
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
// Ruta para iniciar el flujo OAuth
|
|
124
|
+
router.get('/auth/google', (req, res) => {
|
|
125
|
+
// El framework maneja la redirección a Google
|
|
126
|
+
const authMiddleware = authenticator.authenticate('google-oauth');
|
|
127
|
+
authMiddleware(req, res, () => {});
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Paso 3: Crear el endpoint de callback
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
// Ruta para manejar el callback de OAuth
|
|
135
|
+
router.get('/auth/callback', async (req, res) => {
|
|
136
|
+
try {
|
|
137
|
+
// El framework maneja la autenticación y el intercambio de código por token
|
|
138
|
+
const authMiddleware = authenticator.authenticate('google-oauth', {
|
|
139
|
+
failureRedirect: '/login'
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Ejecutar middleware de autenticación
|
|
143
|
+
authMiddleware(req, res, async () => {
|
|
144
|
+
// Si llegamos aquí, la autenticación fue exitosa
|
|
145
|
+
if (req.user) {
|
|
146
|
+
// Generar token JWT para el usuario autenticado
|
|
147
|
+
const token = jwt.sign({
|
|
148
|
+
userId: req.user.id,
|
|
149
|
+
email: req.user.email,
|
|
150
|
+
name: req.user.name
|
|
151
|
+
}, process.env.JWT_SECRET);
|
|
152
|
+
|
|
153
|
+
// Redirigir con token o mostrar página de éxito
|
|
154
|
+
res.writeHead(302, { 'Location': `/dashboard?token=${token}` });
|
|
155
|
+
res.end();
|
|
156
|
+
} else {
|
|
157
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
158
|
+
res.end(JSON.stringify({ error: 'Autenticación fallida' }));
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error('Error en callback OAuth:', error);
|
|
163
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
164
|
+
res.end(JSON.stringify({ error: 'Error interno del servidor' }));
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Manejo de Tokens
|
|
170
|
+
|
|
171
|
+
### Paso 1: Configurar TokenManager
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
const tokenManager = new TokenManager({
|
|
175
|
+
storage: 'memory' // Opciones: 'memory', 'json', 'database'
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Paso 2: Generar tokens JWT
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
// Generar token JWT después de autenticación exitosa
|
|
183
|
+
const generateToken = (userData) => {
|
|
184
|
+
return jwt.sign(
|
|
185
|
+
{
|
|
186
|
+
userId: userData.id,
|
|
187
|
+
email: userData.email,
|
|
188
|
+
name: userData.name,
|
|
189
|
+
provider: 'google'
|
|
190
|
+
},
|
|
191
|
+
process.env.JWT_SECRET,
|
|
192
|
+
{ expiresIn: '1h' }
|
|
193
|
+
);
|
|
194
|
+
};
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Paso 3: Validar tokens
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
// Middleware para validar tokens JWT
|
|
201
|
+
const validateToken = (req, res, next) => {
|
|
202
|
+
const authHeader = req.headers.authorization;
|
|
203
|
+
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
|
204
|
+
|
|
205
|
+
if (!token) {
|
|
206
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
207
|
+
res.end(JSON.stringify({ error: 'Token no proporcionado' }));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
|
|
212
|
+
if (err) {
|
|
213
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
214
|
+
res.end(JSON.stringify({ error: 'Token inválido' }));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
req.user = decoded;
|
|
219
|
+
next();
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Protección de Endpoints
|
|
225
|
+
|
|
226
|
+
### Paso 1: Proteger rutas individuales
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
// Proteger una ruta específica
|
|
230
|
+
router.get('/profile', validateToken, (req, res) => {
|
|
231
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
232
|
+
res.end(JSON.stringify({
|
|
233
|
+
user: req.user,
|
|
234
|
+
message: 'Perfil de usuario protegido'
|
|
235
|
+
}));
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Paso 2: Proteger rutas usando el framework
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
// Usar la estrategia JWT del framework
|
|
243
|
+
authenticator.use('jwt-auth', (req, options = {}) => {
|
|
244
|
+
const authHeader = req.headers.authorization;
|
|
245
|
+
const token = authHeader && authHeader.split(' ')[1];
|
|
246
|
+
|
|
247
|
+
if (!token) return false;
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
|
251
|
+
req.user = decoded;
|
|
252
|
+
return true;
|
|
253
|
+
} catch (error) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Proteger ruta con autenticación JWT
|
|
259
|
+
router.get('/protected', authenticator.authenticate('jwt-auth'), (req, res) => {
|
|
260
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
261
|
+
res.end(JSON.stringify({ message: 'Contenido protegido', user: req.user }));
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Consideraciones de Seguridad
|
|
266
|
+
|
|
267
|
+
### 1. Almacenamiento de credenciales
|
|
268
|
+
|
|
269
|
+
- Nunca almacenes credenciales en el código fuente
|
|
270
|
+
- Usa variables de entorno o servicios de gestión de secretos
|
|
271
|
+
- Rotar periódicamente los secrets
|
|
272
|
+
|
|
273
|
+
### 2. Validación de tokens
|
|
274
|
+
|
|
275
|
+
- Siempre valida tokens antes de conceder acceso
|
|
276
|
+
- Implementa expiración de tokens
|
|
277
|
+
- Considera usar refresh tokens para largas sesiones
|
|
278
|
+
|
|
279
|
+
### 3. Configuración de Google
|
|
280
|
+
|
|
281
|
+
- Limita las URLs de redirección a solo las que necesitas
|
|
282
|
+
- Usa HTTPS en producción
|
|
283
|
+
- Monitorea el uso de tus credenciales
|
|
284
|
+
|
|
285
|
+
### 4. Manejo de errores
|
|
286
|
+
|
|
287
|
+
- No reveles información sensible en mensajes de error
|
|
288
|
+
- Implementa logging adecuado para auditoría
|
|
289
|
+
- Maneja correctamente los casos de fallo de autenticación
|
|
290
|
+
|
|
291
|
+
## Depuración y Troubleshooting
|
|
292
|
+
|
|
293
|
+
### Problemas comunes y soluciones
|
|
294
|
+
|
|
295
|
+
#### 1. Error: "redirect_uri_mismatch"
|
|
296
|
+
- **Causa**: La URL de redirección no coincide con las registradas en Google Cloud Console
|
|
297
|
+
- **Solución**: Verifica que la URL en tu código coincida exactamente con las registradas
|
|
298
|
+
|
|
299
|
+
#### 2. Error: "invalid_client"
|
|
300
|
+
- **Causa**: Client ID o Client Secret incorrectos
|
|
301
|
+
- **Solución**: Verifica que las credenciales sean correctas y no estén truncadas
|
|
302
|
+
|
|
303
|
+
#### 3. Token expirado
|
|
304
|
+
- **Causa**: El access token ha expirado
|
|
305
|
+
- **Solución**: Implementa refresh tokens o solicita nuevo acceso
|
|
306
|
+
|
|
307
|
+
### Herramientas de depuración
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
// Habilitar logging detallado
|
|
311
|
+
const logger = new Logger({ level: 'debug' });
|
|
312
|
+
|
|
313
|
+
// Verificar estado de autenticación
|
|
314
|
+
console.log('Usuario autenticado:', req.user);
|
|
315
|
+
console.log('Headers:', req.headers);
|
|
316
|
+
console.log('Query params:', req.query);
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Pruebas
|
|
320
|
+
|
|
321
|
+
```javascript
|
|
322
|
+
// Prueba de endpoint protegido
|
|
323
|
+
const testProtectedEndpoint = async (token) => {
|
|
324
|
+
const response = await fetch('http://localhost:8093/protected', {
|
|
325
|
+
headers: {
|
|
326
|
+
'Authorization': `Bearer ${token}`
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
const data = await response.json();
|
|
331
|
+
console.log('Respuesta del endpoint protegido:', data);
|
|
332
|
+
};
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Ejemplo Completo
|
|
336
|
+
|
|
337
|
+
Aquí tienes un ejemplo completo de implementación:
|
|
338
|
+
|
|
339
|
+
```javascript
|
|
340
|
+
const {
|
|
341
|
+
APIServer,
|
|
342
|
+
Authenticator,
|
|
343
|
+
Router,
|
|
344
|
+
Logger
|
|
345
|
+
} = require('apisdk');
|
|
346
|
+
|
|
347
|
+
const jwt = require('jsonwebtoken');
|
|
348
|
+
|
|
349
|
+
async function startServer() {
|
|
350
|
+
const server = new APIServer({
|
|
351
|
+
port: 8093,
|
|
352
|
+
host: 'localhost'
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const logger = new Logger({ level: 'info' });
|
|
356
|
+
const router = new Router();
|
|
357
|
+
const authenticator = new Authenticator({ logger });
|
|
358
|
+
|
|
359
|
+
// Configurar estrategia OAuth2
|
|
360
|
+
authenticator.use('google-oauth', authenticator.oauth2Strategy({
|
|
361
|
+
clientId: process.env.OAUTH_CLIENT_ID,
|
|
362
|
+
clientSecret: process.env.OAUTH_CLIENT_SECRET,
|
|
363
|
+
callbackURL: process.env.OAUTH_CALLBACK_URL,
|
|
364
|
+
}));
|
|
365
|
+
|
|
366
|
+
// Agregar autenticador al servidor
|
|
367
|
+
server.authenticator = authenticator;
|
|
368
|
+
|
|
369
|
+
// Ruta para iniciar OAuth
|
|
370
|
+
router.get('/auth/google', (req, res) => {
|
|
371
|
+
authenticator.authenticate('google-oauth')(req, res, () => {});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Ruta de callback
|
|
375
|
+
router.get('/auth/callback', (req, res) => {
|
|
376
|
+
authenticator.authenticate('google-oauth', {
|
|
377
|
+
successRedirect: '/dashboard',
|
|
378
|
+
failureRedirect: '/login'
|
|
379
|
+
})(req, res, () => {});
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// Ruta protegida
|
|
383
|
+
router.get('/dashboard', (req, res) => {
|
|
384
|
+
if (req.user) {
|
|
385
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
386
|
+
res.end(JSON.stringify({ message: 'Bienvenido al dashboard', user: req.user }));
|
|
387
|
+
} else {
|
|
388
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
389
|
+
res.end(JSON.stringify({ error: 'No autorizado' }));
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Agregar rutas al servidor
|
|
394
|
+
for (const route of router.getRoutes()) {
|
|
395
|
+
server.addRoute(route.method, route.path, route.handler);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
server.start();
|
|
399
|
+
logger.info('Servidor iniciado en http://localhost:8093');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
startServer();
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Este manual proporciona una guía completa para implementar OAuth 2.0 con Google usando el Framework API SDK, desde la configuración inicial hasta la implementación completa y consideraciones de seguridad.
|
|
@@ -47,7 +47,7 @@ El framework ahora puede servir diferentes tipos de contenido:
|
|
|
47
47
|
Para usar el sistema de sesiones, primero debes configurar el middleware en tu aplicación:
|
|
48
48
|
|
|
49
49
|
```javascript
|
|
50
|
-
const { APIServer, SessionManager, Cors } = require('
|
|
50
|
+
const { APIServer, SessionManager, Cors } = require('@apisdkjs/apisdkjs');
|
|
51
51
|
|
|
52
52
|
async function startServer() {
|
|
53
53
|
const server = new APIServer({
|
|
@@ -187,7 +187,7 @@ El sistema de sesiones está completamente integrado con el sistema de hooks, fi
|
|
|
187
187
|
#### Registrar actividad de sesión
|
|
188
188
|
|
|
189
189
|
```javascript
|
|
190
|
-
const { hooks } = require('
|
|
190
|
+
const { hooks } = require('@apisdkjs/apisdkjs');
|
|
191
191
|
|
|
192
192
|
// Registrar cuando se crea una sesión
|
|
193
193
|
hooks.addAction('session_created', (sessionId, sessionData) => {
|
|
@@ -203,7 +203,7 @@ hooks.addAction('session_destroyed', (sessionId, sessionData) => {
|
|
|
203
203
|
#### Modificar datos de sesión antes de crearla
|
|
204
204
|
|
|
205
205
|
```javascript
|
|
206
|
-
const { hooks } = require('
|
|
206
|
+
const { hooks } = require('@apisdkjs/apisdkjs');
|
|
207
207
|
|
|
208
208
|
// Añadir información de IP y fecha a los datos de sesión
|
|
209
209
|
hooks.addFilter('session_create_data', (userData, req) => {
|
|
@@ -218,7 +218,7 @@ hooks.addFilter('session_create_data', (userData, req) => {
|
|
|
218
218
|
#### Personalizar el manejo de autenticación fallida
|
|
219
219
|
|
|
220
220
|
```javascript
|
|
221
|
-
const { hooks } = require('
|
|
221
|
+
const { hooks } = require('@apisdkjs/apisdkjs');
|
|
222
222
|
|
|
223
223
|
// Registrar intentos de acceso no autorizado
|
|
224
224
|
hooks.addAction('session_auth_failed', (req, res, redirectTo) => {
|
|
@@ -235,7 +235,7 @@ hooks.addAction('session_auth_failed', (req, res, redirectTo) => {
|
|
|
235
235
|
#### Extender datos de sesión durante la actualización
|
|
236
236
|
|
|
237
237
|
```javascript
|
|
238
|
-
const { hooks } = require('
|
|
238
|
+
const { hooks } = require('@apisdkjs/apisdkjs');
|
|
239
239
|
|
|
240
240
|
// Añadir marca de tiempo a cada actualización de sesión
|
|
241
241
|
hooks.addFilter('session_update_data', (newData, req, sessionId) => {
|
|
@@ -259,7 +259,7 @@ const {
|
|
|
259
259
|
Logger,
|
|
260
260
|
Cors,
|
|
261
261
|
SessionManager
|
|
262
|
-
} = require('
|
|
262
|
+
} = require('@apisdkjs/apisdkjs');
|
|
263
263
|
|
|
264
264
|
async function startServer() {
|
|
265
265
|
const server = new APIServer({
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controlador de ejemplo para productos
|
|
3
|
+
* Archivo: examples/advanced/controllers/productController.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Simulación de base de datos de productos
|
|
7
|
+
let products = [
|
|
8
|
+
{ id: 1, name: 'Laptop', price: 1000, category: 'Electronics' },
|
|
9
|
+
{ id: 2, name: 'Mouse', price: 25, category: 'Accessories' }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
// Obtener todos los productos
|
|
13
|
+
function getProducts(req, res) {
|
|
14
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
15
|
+
res.end(JSON.stringify({
|
|
16
|
+
success: true,
|
|
17
|
+
data: products
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Actualizar un producto por ID
|
|
22
|
+
function updateProduct(req, res) {
|
|
23
|
+
try {
|
|
24
|
+
const productId = parseInt(req.params.id);
|
|
25
|
+
const { name, price, category } = req.body;
|
|
26
|
+
|
|
27
|
+
const productIndex = products.findIndex(p => p.id === productId);
|
|
28
|
+
|
|
29
|
+
if (productIndex === -1) {
|
|
30
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
31
|
+
res.end(JSON.stringify({
|
|
32
|
+
success: false,
|
|
33
|
+
message: 'Producto no encontrado'
|
|
34
|
+
}));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Actualizar producto
|
|
39
|
+
products[productIndex] = {
|
|
40
|
+
...products[productIndex],
|
|
41
|
+
...(name && { name }),
|
|
42
|
+
...(price && { price }),
|
|
43
|
+
...(category && { category })
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
47
|
+
res.end(JSON.stringify({
|
|
48
|
+
success: true,
|
|
49
|
+
data: products[productIndex]
|
|
50
|
+
}));
|
|
51
|
+
} catch (error) {
|
|
52
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
53
|
+
res.end(JSON.stringify({
|
|
54
|
+
success: false,
|
|
55
|
+
message: 'Error al actualizar producto'
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Exportar handlers
|
|
61
|
+
module.exports = {
|
|
62
|
+
getProducts,
|
|
63
|
+
updateProduct
|
|
64
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controlador de ejemplo para usuarios
|
|
3
|
+
* Archivo: examples/basic/controllers/userController.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Simulación de base de datos
|
|
7
|
+
let users = [
|
|
8
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com' },
|
|
9
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
// Obtener todos los usuarios
|
|
13
|
+
function getUsers(req, res) {
|
|
14
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
15
|
+
res.end(JSON.stringify({
|
|
16
|
+
success: true,
|
|
17
|
+
data: users
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Obtener un usuario por ID
|
|
22
|
+
function getUserById(req, res) {
|
|
23
|
+
const userId = parseInt(req.params.id);
|
|
24
|
+
const user = users.find(u => u.id === userId);
|
|
25
|
+
|
|
26
|
+
if (!user) {
|
|
27
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
28
|
+
res.end(JSON.stringify({
|
|
29
|
+
success: false,
|
|
30
|
+
message: 'Usuario no encontrado'
|
|
31
|
+
}));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
36
|
+
res.end(JSON.stringify({
|
|
37
|
+
success: true,
|
|
38
|
+
data: user
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Crear un nuevo usuario
|
|
43
|
+
function createUser(req, res) {
|
|
44
|
+
try {
|
|
45
|
+
const { name, email } = req.body;
|
|
46
|
+
|
|
47
|
+
// Validar datos
|
|
48
|
+
if (!name || !email) {
|
|
49
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
50
|
+
res.end(JSON.stringify({
|
|
51
|
+
success: false,
|
|
52
|
+
message: 'Nombre y correo electrónico son requeridos'
|
|
53
|
+
}));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Crear nuevo usuario
|
|
58
|
+
const newUser = {
|
|
59
|
+
id: users.length + 1,
|
|
60
|
+
name,
|
|
61
|
+
email
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
users.push(newUser);
|
|
65
|
+
|
|
66
|
+
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
67
|
+
res.end(JSON.stringify({
|
|
68
|
+
success: true,
|
|
69
|
+
data: newUser
|
|
70
|
+
}));
|
|
71
|
+
} catch (error) {
|
|
72
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
73
|
+
res.end(JSON.stringify({
|
|
74
|
+
success: false,
|
|
75
|
+
message: 'Error al crear usuario'
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Exportar handlers
|
|
81
|
+
module.exports = {
|
|
82
|
+
getUsers,
|
|
83
|
+
getUserById,
|
|
84
|
+
createUser
|
|
85
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"path": "/api/users",
|
|
4
|
+
"method": "GET",
|
|
5
|
+
"auth": "jwt",
|
|
6
|
+
"authOptions": {
|
|
7
|
+
"jwtSecret": "secret-jwt-key"
|
|
8
|
+
},
|
|
9
|
+
"controller": "./basic/controllers/userController.js",
|
|
10
|
+
"handler": "getUsers"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"path": "/api/users/:id",
|
|
14
|
+
"method": "GET",
|
|
15
|
+
"auth": "jwt",
|
|
16
|
+
"authOptions": {
|
|
17
|
+
"jwtSecret": "secret-jwt-key"
|
|
18
|
+
},
|
|
19
|
+
"controller": "./basic/controllers/userController.js",
|
|
20
|
+
"handler": "getUserById"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"path": "/api/users",
|
|
24
|
+
"method": "POST",
|
|
25
|
+
"auth": "apiKey",
|
|
26
|
+
"authOptions": {
|
|
27
|
+
"apiKeyHeader": "X-API-Key",
|
|
28
|
+
"apiKeyValues": ["secret-key-123"]
|
|
29
|
+
},
|
|
30
|
+
"controller": "./basic/controllers/userController.js",
|
|
31
|
+
"handler": "createUser"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"path": "/api/products",
|
|
35
|
+
"method": "GET",
|
|
36
|
+
"auth": "none",
|
|
37
|
+
"controller": "./advanced/controllers/productController.js",
|
|
38
|
+
"handler": "getProducts"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"path": "/api/products/:id",
|
|
42
|
+
"method": "PUT",
|
|
43
|
+
"auth": "apiKey",
|
|
44
|
+
"authOptions": {
|
|
45
|
+
"apiKeyHeader": "X-API-Key",
|
|
46
|
+
"apiKeyValues": ["secret-key-123"]
|
|
47
|
+
},
|
|
48
|
+
"controller": "./advanced/controllers/productController.js",
|
|
49
|
+
"handler": "updateProduct"
|
|
50
|
+
}
|
|
51
|
+
]
|