En este ejercicio avanzado, se te desafía a implementar un sistema cliente-servidor en Java que no solo gestione usuarios y sesiones, sino que también implemente control de acceso basado en roles. Este ejercicio te ayudará a profundizar en conceptos clave como la autenticación, autorización, y la implementación de roles de usuario para controlar el acceso a diferentes recursos.
Ejercicio: Implementación de un Sistema Cliente-Servidor con Gestión de Usuarios, Roles y Control de Acceso
Objetivo:
Desarrollar un servidor HTTP en Java que permita:
- Registro de usuarios: El servidor debe permitir que los usuarios se registren proporcionando un nombre de usuario, contraseña y un rol (por ejemplo, “admin” o “user”).
- Inicio de sesión: Los usuarios registrados deben poder iniciar sesión proporcionando sus credenciales.
- Gestión de sesiones: El servidor debe generar un token de sesión único para cada inicio de sesión exitoso.
- Control de acceso basado en roles: Dependiendo del rol del usuario, este podrá acceder a diferentes recursos protegidos.
- Roles de usuario: Los roles deben ser “admin” y “user”, donde “admin” tiene acceso completo y “user” acceso limitado.
Requisitos:
- Puerto de Escucha: El servidor debe escuchar en el puerto 8086.
- Registro de Usuarios: El cliente debe poder registrar un usuario enviando un nombre de usuario, contraseña, y rol a la ruta
/register
mediante una solicitud POST. - Inicio de Sesión: El cliente debe poder iniciar sesión enviando un nombre de usuario y contraseña a la ruta
/login
mediante una solicitud POST. - Gestión de Sesiones: El servidor debe generar un token de sesión único para cada inicio de sesión exitoso.
- Control de Acceso: Los recursos protegidos deben ser accesibles según el rol del usuario:
- /admin: Solo accesible para usuarios con rol “admin”.
- /user: Accesible para usuarios con rol “user” y “admin”.
- Validación del token: El servidor debe validar el token de sesión para conceder o denegar el acceso a los recursos protegidos.
Parte 1: Implementación del Servidor HTTP en Java
El servidor gestionará el registro de usuarios, el inicio de sesión, la validación de tokens, y el control de acceso basado en roles.
Código del Servidor:
package cristinaleonacademiaexamen;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executors;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
public class ServidorHTTP {
private static Map<String, Usuario> usuarios = new HashMap<>();
private static Map<String, String> sesiones = new HashMap<>();
public static void main(String[] args) throws IOException {
HttpServer server = HttpServer.create(new InetSocketAddress(8086), 0);
server.createContext("/register", new RegistroHandler());
server.createContext("/login", new LoginHandler());
server.createContext("/admin", new AdminHandler());
server.createContext("/user", new UserHandler());
server.setExecutor(Executors.newCachedThreadPool()); // Manejo concurrente de solicitudes
server.start();
System.out.println("Servidor HTTP iniciado en el puerto 8086");
}
static class RegistroHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
if ("POST".equals(exchange.getRequestMethod())) {
String[] credenciales = new String(exchange.getRequestBody().readAllBytes()).split("&");
String nombreUsuario = credenciales[0].split("=")[1];
String password = credenciales[1].split("=")[1];
String rol = credenciales[2].split("=")[1];
if (usuarios.containsKey(nombreUsuario)) {
String respuesta = "Usuario ya registrado.";
exchange.sendResponseHeaders(409, respuesta.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(respuesta.getBytes());
os.close();
} else {
usuarios.put(nombreUsuario, new Usuario(nombreUsuario, password, rol));
String respuesta = "Usuario registrado con éxito.";
exchange.sendResponseHeaders(200, respuesta.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(respuesta.getBytes());
os.close();
}
} else {
exchange.sendResponseHeaders(405, -1); // Método no permitido
}
}
}
static class LoginHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
if ("POST".equals(exchange.getRequestMethod())) {
String[] credenciales = new String(exchange.getRequestBody().readAllBytes()).split("&");
String nombreUsuario = credenciales[0].split("=")[1];
String password = credenciales[1].split("=")[1];
if (usuarios.containsKey(nombreUsuario) && usuarios.get(nombreUsuario).getPassword().equals(password)) {
String token = UUID.randomUUID().toString();
sesiones.put(token, nombreUsuario);
String respuesta = "Inicio de sesión exitoso. Token de sesión: " + token;
exchange.sendResponseHeaders(200, respuesta.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(respuesta.getBytes());
os.close();
} else {
String respuesta = "Credenciales incorrectas.";
exchange.sendResponseHeaders(401, respuesta.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(respuesta.getBytes());
os.close();
}
} else {
exchange.sendResponseHeaders(405, -1); // Método no permitido
}
}
}
static class AdminHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
String token = exchange.getRequestHeaders().getFirst("Authorization");
if (sesiones.containsKey(token)) {
String nombreUsuario = sesiones.get(token);
Usuario usuario = usuarios.get(nombreUsuario);
if ("admin".equals(usuario.getRol())) {
String respuesta = "Acceso concedido al recurso admin para el usuario: " + nombreUsuario;
exchange.sendResponseHeaders(200, respuesta.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(respuesta.getBytes());
os.close();
} else {
String respuesta = "Acceso denegado. Este recurso es solo para administradores.";
exchange.sendResponseHeaders(403, respuesta.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(respuesta.getBytes());
os.close();
}
} else {
String respuesta = "No autorizado. Token de sesión inválido.";
exchange.sendResponseHeaders(403, respuesta.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(respuesta.getBytes());
os.close();
}
}
}
static class UserHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
String token = exchange.getRequestHeaders().getFirst("Authorization");
if (sesiones.containsKey(token)) {
String nombreUsuario = sesiones.get(token);
Usuario usuario = usuarios.get(nombreUsuario);
String respuesta = "Acceso concedido al recurso user para el usuario: " + nombreUsuario + " con rol: " + usuario.getRol();
exchange.sendResponseHeaders(200, respuesta.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(respuesta.getBytes());
os.close();
} else {
String respuesta = "No autorizado. Token de sesión inválido.";
exchange.sendResponseHeaders(403, respuesta.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(respuesta.getBytes());
os.close();
}
}
}
static class Usuario {
private String nombreUsuario;
private String password;
private String rol;
public Usuario(String nombreUsuario, String password, String rol) {
this.nombreUsuario = nombreUsuario;
this.password = password;
this.rol = rol;
}
public String getNombreUsuario() {
return nombreUsuario;
}
public String getPassword() {
return password;
}
public String getRol() {
return rol;
}
}
}
Explicación del Código:
- Gestión de Usuarios con Roles:
- Los usuarios se registran mediante la ruta
/register
, enviando un nombre de usuario, contraseña, y rol (“admin” o “user”). - La clase
Usuario
almacena la información de cada usuario, incluyendo su rol.
- Inicio de Sesión y Generación de Tokens:
- La ruta
/login
permite a los usuarios iniciar sesión. Si las credenciales son correctas, se genera un token de sesión único.
- Control de Acceso Basado en Roles:
- La ruta
/admin
es accesible solo para usuarios con rol “admin”. Si un usuario con un rol diferente intenta acceder, se deniega el acceso. - La ruta
/user
es accesible para cualquier usuario autenticado, tanto “user” como “admin”.
- Validación del Token de Sesión:
- El servidor verifica que el token de sesión sea válido antes de conceder acceso a los recursos protegidos.
**Parte 2
: Implementación del Cliente Java**
El cliente interactuará con el servidor para registrar usuarios, iniciar sesión, y acceder a recursos protegidos según el rol del usuario.
Código del Cliente:
package cristinaleonacademiaexamen;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class ClienteHTTP {
public static void main(String[] args) {
try {
// Registro de usuario como admin
String urlRegistro = "http://localhost:8086/register";
String credencialesRegistro = "usuarioAdmin=passwordAdmin&rol=admin";
String respuestaRegistro = enviarSolicitudPost(urlRegistro, credencialesRegistro);
System.out.println("Respuesta del servidor (Registro): " + respuestaRegistro);
// Inicio de sesión
String urlLogin = "http://localhost:8086/login";
String credencialesLogin = "usuarioAdmin=passwordAdmin";
String token = autenticarUsuario(urlLogin, credencialesLogin);
System.out.println("Token de sesión: " + token);
// Acceso a recurso admin usando el token
String urlAdmin = "http://localhost:8086/admin";
String respuestaAdmin = accederRecursoProtegido(urlAdmin, token);
System.out.println("Respuesta del recurso admin: " + respuestaAdmin);
// Acceso a recurso user usando el token
String urlUser = "http://localhost:8086/user";
String respuestaUser = accederRecursoProtegido(urlUser, token);
System.out.println("Respuesta del recurso user: " + respuestaUser);
} catch (Exception e) {
e.printStackTrace();
}
}
private static String enviarSolicitudPost(String urlStr, String datos) throws Exception {
URL url = new URL(urlStr);
HttpURLConnection conexion = (HttpURLConnection) url.openConnection();
conexion.setRequestMethod("POST");
conexion.setDoOutput(true);
try (OutputStream os = conexion.getOutputStream()) {
os.write(datos.getBytes());
os.flush();
}
BufferedReader in = new BufferedReader(new InputStreamReader(conexion.getInputStream()));
String inputLine;
StringBuilder contenido = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
contenido.append(inputLine);
}
in.close();
return contenido.toString();
}
private static String autenticarUsuario(String urlStr, String credenciales) throws Exception {
String respuesta = enviarSolicitudPost(urlStr, credenciales);
return extraerTokenDeRespuesta(respuesta);
}
private static String extraerTokenDeRespuesta(String respuesta) {
int inicio = respuesta.indexOf("Token de sesión: ") + 17;
return respuesta.substring(inicio);
}
private static String accederRecursoProtegido(String urlStr, String token) throws Exception {
URL url = new URL(urlStr);
HttpURLConnection conexion = (HttpURLConnection) url.openConnection();
conexion.setRequestMethod("GET");
conexion.setRequestProperty("Authorization", token);
BufferedReader in = new BufferedReader(new InputStreamReader(conexion.getInputStream()));
String inputLine;
StringBuilder contenido = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
contenido.append(inputLine);
}
in.close();
return contenido.toString();
}
}
Explicación del Código:
- Registro de Usuarios con Rol:
- El cliente envía una solicitud POST al servidor con las credenciales y el rol del nuevo usuario. El servidor responde si el registro fue exitoso.
- Inicio de Sesión:
- El cliente envía las credenciales a la ruta
/login
. Si el inicio de sesión es exitoso, el servidor devuelve un token de sesión.
- Acceso a Recursos Protegidos según el Rol:
- El cliente utiliza el token de sesión para acceder a recursos protegidos en las rutas
/admin
y/user
. - La ruta
/admin
solo es accesible para usuarios con el rol “admin”, mientras que la ruta/user
es accesible para todos los usuarios autenticados.
- Métodos Auxiliares:
enviarSolicitudPost
: Envía una solicitud POST al servidor con los datos proporcionados.autenticarUsuario
: Gestiona el proceso de inicio de sesión y obtiene el token de sesión.accederRecursoProtegido
: Envía una solicitud GET al recurso protegido utilizando el token de sesión.
Conclusión
Este ejercicio avanzado de cliente-servidor en Java te permite implementar un sistema completo que gestiona usuarios, roles, y acceso a recursos protegidos. La implementación de roles agrega un nivel adicional de complejidad y seguridad, asegurando que solo los usuarios con los permisos adecuados puedan acceder a ciertos recursos. Este ejercicio es ideal para prepararte para situaciones más complejas en un examen o en la vida profesional, al proporcionar una comprensión profunda de cómo implementar seguridad y control de acceso en sistemas distribuidos en Java. ¡Espero que lo encuentres desafiante y útil para tu aprendizaje!
… … …
¡Coméntanos que te ha parecido este artículo al final de la página!
TÚ OPINIÓN IMPORTA
NUESTRAS ÚLTIMAS PUBLICACIONES
- Artículo: Funciones esenciales de C para la manipulación de cadenas: fgets, strlen, stdin, y más
- Uso de la Clase DAO sin Interfaces en Java: Ejemplo de Gestión de Trabajadores
- Uso de DAO en Java: Simplificando el Acceso a Datos con el Patrón DAO
- Guía Completa para la Creación de Gramáticas en JFLAP: Ejercicios y Soluciones
- Generación de Lenguajes en JFLAP con Gramáticas: Ejercicios y Estrategias
- Máquinas de Turing y Enumeración de Números Binarios: Diseño y Funcionamiento en JFLAP
- Generación de Documentación en C++ con Doxygen: Guía Completa
- La importancia de separar sustantivos, adjetivos y verbos en programación y bases de datos
- Entendiendo los Símbolos de Lenguajes y Autómatas en Computación
Contenido restringido
Comments are closed