Arquitectura del sistema
-
Frontend:
- Un formulario interactivo donde el usuario pueda registrarse.
- Campo para nombre de usuario y contraseña.
-
Backend:
- Endpoint para manejar el registro de usuarios.
- Almacenamiento seguro de contraseñas utilizando técnicas como hashing (con bcrypt).
- Endpoint para autenticación de usuarios mediante login.
- Implementación de validación avanzada.
1. Backend: Registro y autenticación avanzada
Código backend en C
- Este código agrega funcionalidades para registro de usuarios, almacenamiento seguro de contraseñas y autenticación.
Archivo: auth_handler.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include "auth_handler.h"
#define MAX_USERS 100
#define USERNAME_LENGTH 50
#define PASSWORD_HASH_LENGTH 128
typedef struct {
char username[USERNAME_LENGTH];
char password_hash[PASSWORD_HASH_LENGTH];
} User;
User users[MAX_USERS];
int user_count = 0;
// Función para generar hash seguro
void generate_hash(const char *password, char *hash_output) {
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int hash_len;
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
const EVP_MD *md = EVP_sha256();
EVP_DigestInit_ex(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, password, strlen(password));
EVP_DigestFinal_ex(mdctx, hash, &hash_len);
EVP_MD_CTX_free(mdctx);
// Convertir el hash a string hexadecimal
for (unsigned int i = 0; i < hash_len; i++) {
sprintf(hash_output + (i * 2), "%02x", hash[i]);
}
}
// Registro de usuarios
int register_user(const char *username, const char *password) {
if (user_count >= MAX_USERS) {
return 0; // No se pueden registrar más usuarios
}
for (int i = 0; i < user_count; i++) {
if (strcmp(users[i].username, username) == 0) {
return -1; // Usuario ya registrado
}
}
strncpy(users[user_count].username, username, USERNAME_LENGTH);
generate_hash(password, users[user_count].password_hash);
user_count++;
return 1; // Registro exitoso
}
// Autenticación de usuarios
int authenticate_user(const char *username, const char *password) {
char hash[PASSWORD_HASH_LENGTH];
generate_hash(password, hash);
for (int i = 0; i < user_count; i++) {
if (strcmp(users[i].username, username) == 0 &&
strcmp(users[i].password_hash, hash) == 0) {
return 1; // Autenticación exitosa
}
}
return 0; // Autenticación fallida
}
Archivo: auth_handler.h
#ifndef AUTH_HANDLER_H
#define AUTH_HANDLER_H
int register_user(const char *username, const char *password);
int authenticate_user(const char *username, const char *password);
#endif
2. Backend: Endpoint HTTP para registro y autenticación
Actualiza el servidor para manejar solicitudes de registro y autenticación.
Agregar lógica al request_handler.c
#include "auth_handler.h"
void handle_register_request(int client_socket, const char *body) {
char username[50], password[50];
sscanf(body, "username=%49s&password=%49s", username, password);
int result = register_user(username, password);
if (result == 1) {
const char *response = "HTTP/1.1 201 Created\r\nContent-Type: text/plain\r\n\r\nUsuario registrado exitosamente.";
write(client_socket, response, strlen(response));
} else if (result == -1) {
const char *response = "HTTP/1.1 409 Conflict\r\nContent-Type: text/plain\r\n\r\nUsuario ya existe.";
write(client_socket, response, strlen(response));
} else {
const char *response = "HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n\r\nNo se puede registrar más usuarios.";
write(client_socket, response, strlen(response));
}
}
void handle_login_request(int client_socket, const char *body) {
char username[50], password[50];
sscanf(body, "username=%49s&password=%49s", username, password);
int result = authenticate_user(username, password);
if (result == 1) {
const char *response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nAutenticación exitosa.";
write(client_socket, response, strlen(response));
} else {
const char *response = "HTTP/1.1 401 Unauthorized\r\nContent-Type: text/plain\r\n\r\nCredenciales inválidas.";
write(client_socket, response, strlen(response));
}
}
3. Frontend: Formulario de registro y autenticación
Código HTML y JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Autenticación avanzada</title>
</head>
<body>
<h1>Registro de Usuario</h1>
<form id="registerForm">
<label for="username">Nombre de usuario:</label>
<input type="text" id="username" name="username" required>
<br>
<label for="password">Contraseña:</label>
<input type="password" id="password" name="password" required>
<br>
<button type="submit">Registrar</button>
</form>
<h1>Inicio de Sesión</h1>
<form id="loginForm">
<label for="usernameLogin">Nombre de usuario:</label>
<input type="text" id="usernameLogin" name="usernameLogin" required>
<br>
<label for="passwordLogin">Contraseña:</label>
<input type="password" id="passwordLogin" name="passwordLogin" required>
<br>
<button type="submit">Iniciar sesión</button>
</form>
<script>
document.getElementById('registerForm').addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
const response = await fetch('/register', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `username=${username}&password=${password}`
});
const result = await response.text();
alert(result);
});
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('usernameLogin').value;
const password = document.getElementById('passwordLogin').value;
const response = await fetch('/login', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `username=${username}&password=${password}`
});
const result = await response.text();
alert(result);
});
</script>
</body>
</html>
¿Es escalable y funcional?
- Funcional: Sí, este sistema puede manejar autenticación básica y permite a los usuarios registrarse y autenticarse desde el frontend.
- Escalable: Es limitado en su estado actual (almacenamiento en memoria). Para hacerlo escalable:
- Implementar bases de datos como MySQL o MongoDB para almacenamiento.
- Usar frameworks modernos como Express.js para el frontend y Flask/Django para el backend.
- Implementar OAuth2 o JWT para una autenticación más robusta.
Cómo usarlo:
- Guarda este código en un archivo llamado
auth.html. - Coloca el archivo en el directorio donde tu servidor puede servirlo, por ejemplo, el directorio raíz del servidor HTTP que implementaste.
- Prueba el archivo accediendo desde tu navegador en
http://localhost:8080/auth.html.
Consideraciones:
- El formulario de registro envía datos al endpoint
/registerde tu backend, que maneja la lógica de registro de usuarios. - El formulario de inicio de sesión envía datos al endpoint
/loginde tu backend, que maneja la autenticación.
Tags
Lenguaje C
