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,82 @@
|
|
|
1
|
+
# Ejemplo API con Funcionalidad CORS
|
|
2
|
+
|
|
3
|
+
Este ejemplo demuestra cómo usar la funcionalidad CORS (Cross-Origin Resource Sharing) del Framework JERK.
|
|
4
|
+
|
|
5
|
+
## Características
|
|
6
|
+
|
|
7
|
+
- Configuración de CORS con múltiples orígenes permitidos
|
|
8
|
+
- Configuración de métodos HTTP permitidos
|
|
9
|
+
- Configuración de encabezados permitidos y expuestos
|
|
10
|
+
- Soporte para credenciales
|
|
11
|
+
- Manejo de solicitudes preflight (OPTIONS)
|
|
12
|
+
- Ejemplos de endpoints para probar diferentes aspectos de CORS
|
|
13
|
+
|
|
14
|
+
## Configuración de CORS
|
|
15
|
+
|
|
16
|
+
El ejemplo configura CORS con las siguientes opciones:
|
|
17
|
+
|
|
18
|
+
- **Orígenes permitidos**: `['http://localhost:3000', 'http://localhost:8080', 'https://miapp.com']`
|
|
19
|
+
- **Métodos permitidos**: `['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']`
|
|
20
|
+
- **Encabezados permitidos**: `['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'X-Api-Key']`
|
|
21
|
+
- **Encabezados expuestos**: `['X-Total-Count', 'X-Request-ID']`
|
|
22
|
+
- **Credenciales**: `true` (permite el uso de cookies y encabezados de autenticación)
|
|
23
|
+
- **Max Age**: `86400` (24 horas para caché de preflight)
|
|
24
|
+
|
|
25
|
+
## Uso
|
|
26
|
+
|
|
27
|
+
1. Inicia el servidor:
|
|
28
|
+
```bash
|
|
29
|
+
node app.js
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
2. El servidor escuchará en `http://localhost:8094`
|
|
33
|
+
|
|
34
|
+
## Endpoints
|
|
35
|
+
|
|
36
|
+
- `GET /` - Página de inicio
|
|
37
|
+
- `GET /public` - Endpoint público con CORS habilitado
|
|
38
|
+
- `POST /data` - Endpoint para recibir datos con CORS
|
|
39
|
+
- `GET /test-cors` - Endpoint para probar diferentes encabezados CORS
|
|
40
|
+
|
|
41
|
+
## Pruebas de CORS
|
|
42
|
+
|
|
43
|
+
Puedes probar la funcionalidad CORS desde una aplicación web alojada en uno de los orígenes permitidos:
|
|
44
|
+
|
|
45
|
+
### Ejemplo de solicitud GET:
|
|
46
|
+
```javascript
|
|
47
|
+
fetch('http://localhost:8094/public')
|
|
48
|
+
.then(response => response.json())
|
|
49
|
+
.then(data => console.log(data));
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Ejemplo de solicitud POST con encabezados personalizados:
|
|
53
|
+
```javascript
|
|
54
|
+
fetch('http://localhost:8094/data', {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: {
|
|
57
|
+
'Content-Type': 'application/json',
|
|
58
|
+
'X-Api-Key': 'tu-api-key'
|
|
59
|
+
},
|
|
60
|
+
body: JSON.stringify({ dato: 'ejemplo' })
|
|
61
|
+
})
|
|
62
|
+
.then(response => response.json())
|
|
63
|
+
.then(data => console.log(data));
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Solicitudes complejas que disparan preflight:
|
|
67
|
+
Las solicitudes con encabezados personalizados o ciertos tipos de contenido dispararán una solicitud OPTIONS preflight, que será manejada automáticamente por el middleware CORS.
|
|
68
|
+
|
|
69
|
+
## Estructura del proyecto
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
examples/v2_cors/
|
|
73
|
+
├── app.js # Punto de entrada de la aplicación
|
|
74
|
+
└── README.md
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Notas
|
|
78
|
+
|
|
79
|
+
- El middleware CORS maneja automáticamente las solicitudes preflight (OPTIONS)
|
|
80
|
+
- Los encabezados expuestos son accesibles desde el código JavaScript del cliente
|
|
81
|
+
- Las credenciales permiten el uso de cookies y encabezados de autenticación
|
|
82
|
+
- El encabezado `Access-Control-Max-Age` permite cachear la respuesta preflight
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const {
|
|
2
|
+
APIServer,
|
|
3
|
+
Cors,
|
|
4
|
+
Logger
|
|
5
|
+
} = require('../../index.js');
|
|
6
|
+
|
|
7
|
+
async function startServer() {
|
|
8
|
+
// Crear instancia del servidor
|
|
9
|
+
const server = new APIServer({
|
|
10
|
+
port: 8094,
|
|
11
|
+
host: 'localhost'
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Crear instancia del logger
|
|
15
|
+
const logger = new Logger({ level: 'info' });
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
// Crear instancia del middleware CORS
|
|
19
|
+
const cors = new Cors({
|
|
20
|
+
origin: ['http://localhost:3000', 'http://localhost:8080', 'https://miapp.com'],
|
|
21
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
22
|
+
allowedHeaders: [
|
|
23
|
+
'Content-Type',
|
|
24
|
+
'Authorization',
|
|
25
|
+
'X-Requested-With',
|
|
26
|
+
'Accept',
|
|
27
|
+
'X-Api-Key'
|
|
28
|
+
],
|
|
29
|
+
exposedHeaders: [
|
|
30
|
+
'X-Total-Count',
|
|
31
|
+
'X-Request-ID'
|
|
32
|
+
],
|
|
33
|
+
credentials: true,
|
|
34
|
+
maxAge: 86400 // 24 horas
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Aplicar el middleware CORS al servidor
|
|
38
|
+
server.use(cors.middleware());
|
|
39
|
+
|
|
40
|
+
// Agregar algunas rutas de ejemplo
|
|
41
|
+
server.addRoute('GET', '/', (req, res) => {
|
|
42
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
43
|
+
res.end(JSON.stringify({
|
|
44
|
+
message: 'API con CORS configurado',
|
|
45
|
+
endpoints: {
|
|
46
|
+
'GET /public': 'Endpoint público con CORS',
|
|
47
|
+
'POST /data': 'Endpoint para recibir datos con CORS',
|
|
48
|
+
'GET /test-cors': 'Endpoint para probar diferentes encabezados CORS'
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
server.addRoute('GET', '/public', (req, res) => {
|
|
54
|
+
// Establecer encabezados personalizados que serán expuestos al cliente
|
|
55
|
+
res.setHeader('X-Request-ID', 'req-' + Date.now());
|
|
56
|
+
res.setHeader('X-Total-Count', '100');
|
|
57
|
+
|
|
58
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
59
|
+
res.end(JSON.stringify({
|
|
60
|
+
message: 'Este es un endpoint público con CORS habilitado',
|
|
61
|
+
timestamp: new Date().toISOString(),
|
|
62
|
+
origin: req.headers.origin || 'no origin'
|
|
63
|
+
}));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
server.addRoute('POST', '/data', (req, res) => {
|
|
67
|
+
// Establecer encabezados personalizados
|
|
68
|
+
res.setHeader('X-Request-ID', 'req-' + Date.now());
|
|
69
|
+
|
|
70
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
71
|
+
res.end(JSON.stringify({
|
|
72
|
+
message: 'Datos recibidos exitosamente',
|
|
73
|
+
receivedData: req.body,
|
|
74
|
+
timestamp: new Date().toISOString()
|
|
75
|
+
}));
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
server.addRoute('GET', '/test-cors', (req, res) => {
|
|
79
|
+
// Endpoint para probar diferentes aspectos de CORS
|
|
80
|
+
res.setHeader('X-Request-ID', 'req-' + Date.now());
|
|
81
|
+
res.setHeader('X-Custom-Header', 'custom-value'); // Este encabezado no está en exposedHeaders
|
|
82
|
+
|
|
83
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
84
|
+
res.end(JSON.stringify({
|
|
85
|
+
message: 'Prueba de CORS completada',
|
|
86
|
+
headers: req.headers,
|
|
87
|
+
timestamp: new Date().toISOString()
|
|
88
|
+
}));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Manejar solicitudes OPTIONS para todos los endpoints (preflight)
|
|
92
|
+
// No es necesario agregar una ruta específica para '*' ya que el middleware CORS lo maneja
|
|
93
|
+
|
|
94
|
+
// Iniciar el servidor
|
|
95
|
+
server.start();
|
|
96
|
+
|
|
97
|
+
logger.info('Servidor iniciado en http://localhost:8094');
|
|
98
|
+
logger.info('CORS configurado para orígenes: http://localhost:3000, http://localhost:8080, https://miapp.com');
|
|
99
|
+
} catch (error) {
|
|
100
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Iniciar el servidor
|
|
106
|
+
startServer();
|
|
107
|
+
|
|
108
|
+
module.exports = { startServer };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jerk-cors-example",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Ejemplo de API con funcionalidad CORS usando el Framework JERK",
|
|
5
|
+
"main": "app.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node app.js",
|
|
8
|
+
"dev": "nodemon app.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"api",
|
|
12
|
+
"sdk",
|
|
13
|
+
"cors",
|
|
14
|
+
"cross-origin",
|
|
15
|
+
"security",
|
|
16
|
+
"framework"
|
|
17
|
+
],
|
|
18
|
+
"author": "JERK Framework",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"nodemon": "^3.0.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Ejemplo API con Autenticación JSON
|
|
2
|
+
|
|
3
|
+
Este ejemplo demuestra cómo crear una API con autenticación basada en tokens estáticos almacenados en un archivo JSON utilizando el Framework JERK.
|
|
4
|
+
|
|
5
|
+
## Características
|
|
6
|
+
|
|
7
|
+
- Autenticación JWT con tokens gestionados a través de almacenamiento JSON
|
|
8
|
+
- Rutas protegidas y públicas
|
|
9
|
+
- Sistema de login para obtener tokens
|
|
10
|
+
- Controladores organizados por funcionalidad
|
|
11
|
+
- Tokens almacenados en un archivo JSON local
|
|
12
|
+
|
|
13
|
+
## Configuración
|
|
14
|
+
|
|
15
|
+
1. Asegúrate de tener instaladas las dependencias del framework JERK
|
|
16
|
+
2. El archivo de tokens `tokens.json` se creará automáticamente al iniciar la aplicación
|
|
17
|
+
|
|
18
|
+
## Uso
|
|
19
|
+
|
|
20
|
+
1. Inicia el servidor:
|
|
21
|
+
```bash
|
|
22
|
+
node app.js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. El servidor escuchará en `http://localhost:8091`
|
|
26
|
+
|
|
27
|
+
## Endpoints
|
|
28
|
+
|
|
29
|
+
- `GET /` - Página de inicio (público)
|
|
30
|
+
- `POST /login` - Iniciar sesión y obtener token (público)
|
|
31
|
+
- `GET /protected` - Contenido protegido (requiere token)
|
|
32
|
+
- `GET /profile` - Perfil de usuario (requiere token)
|
|
33
|
+
- `GET /tokens` - Ver tokens almacenados (requiere token)
|
|
34
|
+
|
|
35
|
+
## Ejemplo de uso
|
|
36
|
+
|
|
37
|
+
1. Iniciar sesión:
|
|
38
|
+
```bash
|
|
39
|
+
curl -X POST http://localhost:8091/login \
|
|
40
|
+
-H "Content-Type: application/json" \
|
|
41
|
+
-d '{"username": "admin", "password": "password"}'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. Acceder a contenido protegido:
|
|
45
|
+
```bash
|
|
46
|
+
curl -X GET http://localhost:8091/protected \
|
|
47
|
+
-H "Authorization: Bearer TU_TOKEN_AQUI"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
3. Ver perfil de usuario:
|
|
51
|
+
```bash
|
|
52
|
+
curl -X GET http://localhost:8091/profile \
|
|
53
|
+
-H "Authorization: Bearer TU_TOKEN_AQUI"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
4. Ver tokens almacenados:
|
|
57
|
+
```bash
|
|
58
|
+
curl -X GET http://localhost:8091/tokens \
|
|
59
|
+
-H "Authorization: Bearer TU_TOKEN_AQUI"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Estructura del proyecto
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
examples/v2_json_auth/
|
|
66
|
+
├── app.js # Punto de entrada de la aplicación
|
|
67
|
+
├── routes.json # Definición de rutas
|
|
68
|
+
├── controllers/ # Controladores de las rutas
|
|
69
|
+
│ ├── mainController.js
|
|
70
|
+
│ ├── authController.js
|
|
71
|
+
│ ├── protectedController.js
|
|
72
|
+
│ ├── userController.js
|
|
73
|
+
│ └── tokenController.js
|
|
74
|
+
├── tokens.json # Archivo de almacenamiento de tokens (generado automáticamente)
|
|
75
|
+
└── README.md
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Seguridad
|
|
79
|
+
|
|
80
|
+
- Los tokens se gestionan a través del sistema de TokenManager del framework
|
|
81
|
+
- Los tokens expiran después de 1 hora
|
|
82
|
+
- Las rutas protegidas requieren un token válido en el header Authorization
|
|
83
|
+
- El archivo de tokens se almacena localmente en formato JSON
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const {
|
|
2
|
+
APIServer,
|
|
3
|
+
Authenticator,
|
|
4
|
+
RouteLoader,
|
|
5
|
+
Logger,
|
|
6
|
+
TokenManager
|
|
7
|
+
} = require('../../index.js');
|
|
8
|
+
|
|
9
|
+
async function startServer() {
|
|
10
|
+
// Crear instancia del servidor
|
|
11
|
+
const server = new APIServer({
|
|
12
|
+
port: 8091,
|
|
13
|
+
host: 'localhost'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Crear instancia del logger
|
|
17
|
+
const logger = new Logger({ level: 'info' });
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Crear instancia del TokenManager con almacenamiento en JSON
|
|
21
|
+
const tokenManager = new TokenManager({
|
|
22
|
+
storage: 'json',
|
|
23
|
+
tokenFile: './tokens.json'
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Crear instancia del autenticador
|
|
27
|
+
const authenticator = new Authenticator({ logger });
|
|
28
|
+
|
|
29
|
+
// Registrar estrategia de autenticación JWT que utiliza el TokenManager con almacenamiento JSON
|
|
30
|
+
authenticator.use('jwt-json', async (req, options = {}) => {
|
|
31
|
+
const authHeader = req.headers.authorization;
|
|
32
|
+
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
|
33
|
+
|
|
34
|
+
if (!token) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Validar el token usando el TokenManager
|
|
39
|
+
const secret = 'super-secret-key-for-json-example';
|
|
40
|
+
const decoded = tokenManager.validateToken(token, secret);
|
|
41
|
+
|
|
42
|
+
if (decoded) {
|
|
43
|
+
// Verificar si el token está almacenado en el archivo JSON (opcional, dependiendo del enfoque)
|
|
44
|
+
// En este caso, simplemente verificamos que el token sea válido
|
|
45
|
+
req.user = decoded;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return false;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Agregar el autenticador al servidor para que pueda ser usado por el RouteLoader
|
|
53
|
+
server.authenticator = authenticator;
|
|
54
|
+
|
|
55
|
+
// Cargar rutas desde archivo JSON
|
|
56
|
+
const routeLoader = new RouteLoader();
|
|
57
|
+
await routeLoader.loadRoutes(server, './routes.json');
|
|
58
|
+
|
|
59
|
+
// Iniciar el servidor
|
|
60
|
+
server.start();
|
|
61
|
+
|
|
62
|
+
logger.info('Servidor iniciado en http://localhost:8091');
|
|
63
|
+
} catch (error) {
|
|
64
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Iniciar el servidor
|
|
70
|
+
startServer();
|
|
71
|
+
|
|
72
|
+
module.exports = { startServer };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const jwt = require('jsonwebtoken');
|
|
2
|
+
const { TokenManager } = require('../../../index.js');
|
|
3
|
+
|
|
4
|
+
// TokenManager para este controlador
|
|
5
|
+
const tokenManager = new TokenManager({
|
|
6
|
+
storage: 'json',
|
|
7
|
+
tokenFile: './tokens.json'
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const authController = {
|
|
11
|
+
login: async (req, res) => {
|
|
12
|
+
try {
|
|
13
|
+
const { username, password } = req.body;
|
|
14
|
+
|
|
15
|
+
// Validación simple de credenciales (esto debería ser más robusto en producción)
|
|
16
|
+
if (!username || !password) {
|
|
17
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
18
|
+
res.end(JSON.stringify({ error: 'Nombre de usuario y contraseña requeridos' }));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Simulación de autenticación (en una aplicación real, esto verificaría contra una base de datos)
|
|
23
|
+
if (username === 'admin' && password === 'password') {
|
|
24
|
+
// Generar un token JWT
|
|
25
|
+
const payload = {
|
|
26
|
+
userId: 1,
|
|
27
|
+
username: username,
|
|
28
|
+
role: 'admin'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Secret para firmar el token (en producción, debería estar en variables de entorno)
|
|
32
|
+
const secret = 'super-secret-key-for-json-example';
|
|
33
|
+
const token = jwt.sign(payload, secret, { expiresIn: '1h' });
|
|
34
|
+
|
|
35
|
+
// En este ejemplo con almacenamiento JSON, no almacenamos el token en sí
|
|
36
|
+
// pero podríamos registrar información sobre él si es necesario
|
|
37
|
+
// Alternativamente, podríamos usar el TokenManager para generar un par de tokens
|
|
38
|
+
const tokenPair = tokenManager.generateTokenPair(
|
|
39
|
+
{ userId: 1, username: username, role: 'admin' },
|
|
40
|
+
{
|
|
41
|
+
jwtSecret: secret,
|
|
42
|
+
refreshSecret: 'refresh-' + secret,
|
|
43
|
+
accessExpiresIn: '15m',
|
|
44
|
+
refreshExpiresIn: '7d'
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// Usamos el token de acceso
|
|
49
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
50
|
+
res.end(JSON.stringify({
|
|
51
|
+
message: 'Inicio de sesión exitoso',
|
|
52
|
+
token: tokenPair.accessToken,
|
|
53
|
+
user: payload
|
|
54
|
+
}));
|
|
55
|
+
} else {
|
|
56
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
57
|
+
res.end(JSON.stringify({ error: 'Credenciales inválidas' }));
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('Error en login:', error);
|
|
61
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
62
|
+
res.end(JSON.stringify({ error: 'Error interno del servidor' }));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
module.exports = authController;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const mainController = {
|
|
2
|
+
home: (req, res) => {
|
|
3
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4
|
+
res.end(JSON.stringify({
|
|
5
|
+
message: 'Bienvenido a la API de ejemplo con autenticación JSON',
|
|
6
|
+
endpoints: {
|
|
7
|
+
'POST /login': 'Iniciar sesión y obtener token',
|
|
8
|
+
'GET /protected': 'Contenido protegido (requiere token)',
|
|
9
|
+
'GET /profile': 'Perfil de usuario (requiere token)',
|
|
10
|
+
'GET /tokens': 'Ver tokens almacenados (requiere token)'
|
|
11
|
+
}
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
module.exports = mainController;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const protectedController = {
|
|
2
|
+
getProtectedData: (req, res) => {
|
|
3
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4
|
+
res.end(JSON.stringify({
|
|
5
|
+
message: 'Datos protegidos accesados exitosamente',
|
|
6
|
+
user: req.user,
|
|
7
|
+
timestamp: new Date().toISOString()
|
|
8
|
+
}));
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
module.exports = protectedController;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const { TokenManager } = require('../../../index.js');
|
|
2
|
+
|
|
3
|
+
// TokenManager para este controlador
|
|
4
|
+
const tokenManager = new TokenManager({
|
|
5
|
+
storage: 'json',
|
|
6
|
+
tokenFile: './tokens.json'
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const tokenController = {
|
|
10
|
+
getTokens: (req, res) => {
|
|
11
|
+
try {
|
|
12
|
+
// Obtener todos los tokens almacenados
|
|
13
|
+
const tokens = tokenManager.getAllTokens ? tokenManager.getAllTokens() : 'Método no disponible en esta implementación';
|
|
14
|
+
|
|
15
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
16
|
+
res.end(JSON.stringify({
|
|
17
|
+
message: 'Tokens almacenados',
|
|
18
|
+
tokens: tokens || 'No se pudo obtener la lista de tokens'
|
|
19
|
+
}));
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error('Error obteniendo tokens:', error);
|
|
22
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
23
|
+
res.end(JSON.stringify({ error: 'Error obteniendo tokens' }));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
module.exports = tokenController;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const userController = {
|
|
2
|
+
getProfile: (req, res) => {
|
|
3
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4
|
+
res.end(JSON.stringify({
|
|
5
|
+
profile: {
|
|
6
|
+
id: req.user.userId,
|
|
7
|
+
username: req.user.username || 'Usuario',
|
|
8
|
+
role: req.user.role || 'guest'
|
|
9
|
+
},
|
|
10
|
+
message: 'Perfil de usuario obtenido exitosamente'
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
module.exports = userController;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jerk-json-auth-example",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Ejemplo de API con autenticación JSON usando el Framework JERK",
|
|
5
|
+
"main": "app.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node app.js",
|
|
8
|
+
"dev": "nodemon app.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"api",
|
|
12
|
+
"sdk",
|
|
13
|
+
"authentication",
|
|
14
|
+
"json",
|
|
15
|
+
"jwt",
|
|
16
|
+
"framework"
|
|
17
|
+
],
|
|
18
|
+
"author": "JERK Framework",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"jsonwebtoken": "^9.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"nodemon": "^3.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"path": "/",
|
|
4
|
+
"method": "GET",
|
|
5
|
+
"controller": "./controllers/mainController.js",
|
|
6
|
+
"handler": "home",
|
|
7
|
+
"auth": "none"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"path": "/login",
|
|
11
|
+
"method": "POST",
|
|
12
|
+
"controller": "./controllers/authController.js",
|
|
13
|
+
"handler": "login",
|
|
14
|
+
"auth": "none"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"path": "/protected",
|
|
18
|
+
"method": "GET",
|
|
19
|
+
"controller": "./controllers/protectedController.js",
|
|
20
|
+
"handler": "getProtectedData",
|
|
21
|
+
"auth": "jwt-json"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": "/profile",
|
|
25
|
+
"method": "GET",
|
|
26
|
+
"controller": "./controllers/userController.js",
|
|
27
|
+
"handler": "getProfile",
|
|
28
|
+
"auth": "jwt-json"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"path": "/tokens",
|
|
32
|
+
"method": "GET",
|
|
33
|
+
"controller": "./controllers/tokenController.js",
|
|
34
|
+
"handler": "getTokens",
|
|
35
|
+
"auth": "jwt-json"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example_token": {
|
|
3
|
+
"userId": 0,
|
|
4
|
+
"createdAt": "2026-01-14T00:00:00.000Z",
|
|
5
|
+
"expiresAt": "2026-01-15T00:00:00.000Z",
|
|
6
|
+
"revoked": false
|
|
7
|
+
},
|
|
8
|
+
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInVzZXJuYW1lIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4iLCJ0b2tlblR5cGUiOiJyZWZyZXNoIiwiaWF0IjoxNzY4NDMzODc2LCJleHAiOjE3NjkwMzg2NzZ9.50INL6kmOd9A2mQiBRBlHaXHk31Tw7SgQMH_uRh6NVo": {
|
|
9
|
+
"userId": 1,
|
|
10
|
+
"createdAt": "2026-01-14T23:37:56.407Z",
|
|
11
|
+
"expiresAt": "2026-01-21T23:37:56.407Z",
|
|
12
|
+
"revoked": false
|
|
13
|
+
},
|
|
14
|
+
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInVzZXJuYW1lIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4iLCJ0b2tlblR5cGUiOiJyZWZyZXNoIiwiaWF0IjoxNzY4NDM4NzU4LCJleHAiOjE3NjkwNDM1NTh9.WoMURKAizVPkMM0-lqtl1-mP0L8OMM6INeG5Bv79ixU": {
|
|
15
|
+
"userId": 1,
|
|
16
|
+
"createdAt": "2026-01-15T00:59:18.846Z",
|
|
17
|
+
"expiresAt": "2026-01-22T00:59:18.846Z",
|
|
18
|
+
"revoked": false
|
|
19
|
+
}
|
|
20
|
+
}
|