Sistema de login en Python con archivos TXT

Publicado el: 11/07/2026
Tempo de leitura: 4 minutos
Sistema de login simples desenvolvido com Python

Crear un sistema de login en Python con archivos TXT es un proyecto educativo útil para practicar lectura y escritura de archivos, validación, funciones, manejo de errores y organización de datos. Sin embargo, debe entenderse como un ejercicio local. Un archivo de texto no es una solución adecuada para almacenar credenciales reales en producción, especialmente si guarda contraseñas sin protección.

Qué aprenderás con este proyecto

El objetivo es registrar usuarios, comprobar credenciales y evitar errores comunes. También aprenderás por qué una contraseña nunca debe guardarse como texto visible. Para reforzar la estructura del programa, consulta la guía de funciones en Python.

Estructura del archivo

Podemos utilizar un formato simple con un usuario y un hash separados por dos puntos:

ana:7b3d...
luis:98ac...

Cada línea representa una cuenta. El sistema leerá el archivo, separará los campos y comparará un hash calculado. Este formato sigue siendo limitado, pero es mejor que guardar la contraseña original.

Por qué no guardar contraseñas en texto plano

Si el archivo contiene ana:mi_clave_123, cualquier persona con acceso puede leer la contraseña. Además, muchos usuarios reutilizan claves en otros servicios. Una filtración local puede afectar correos, redes sociales y cuentas bancarias.

Python incluye hashlib para calcular hashes. La documentación oficial de hashlib explica los algoritmos disponibles. Para contraseñas reales se recomiendan funciones especializadas y lentas, como Argon2, bcrypt, scrypt o PBKDF2, con salt y parámetros adecuados.

Crear una función de hash educativo

import hashlib

def crear_hash(contrasena: str) -> str:
    return hashlib.sha256(
        contrasena.encode("utf-8")
    ).hexdigest()

SHA-256 directo sirve para demostrar el concepto, pero no es suficiente para un sistema real porque es demasiado rápido frente a ataques de fuerza bruta. Más adelante veremos una alternativa con PBKDF2.

Leer usuarios desde el archivo

from pathlib import Path

RUTA_USUARIOS = Path("usuarios.txt")

def cargar_usuarios() -> dict[str, str]:
    usuarios = {}
    if not RUTA_USUARIOS.exists():
        return usuarios

    with RUTA_USUARIOS.open(encoding="utf-8") as archivo:
        for numero_linea, linea in enumerate(archivo, start=1):
            linea = linea.strip()
            if not linea:
                continue
            try:
                usuario, hash_guardado = linea.split(":", maxsplit=1)
            except ValueError:
                print(f"Línea inválida: {numero_linea}")
                continue
            usuarios[usuario] = hash_guardado
    return usuarios

La función devuelve un diccionario para búsquedas rápidas. La guía de type hints en Python explica las anotaciones utilizadas.

Registrar un usuario

def registrar_usuario(usuario: str, contrasena: str) -> bool:
    usuario = usuario.strip().lower()
    usuarios = cargar_usuarios()

    if not usuario:
        print("El usuario no puede estar vacío")
        return False

    if usuario in usuarios:
        print("El usuario ya existe")
        return False

    if len(contrasena) < 8:
        print("La contraseña debe tener al menos 8 caracteres")
        return False

    hash_guardado = crear_hash(contrasena)
    with RUTA_USUARIOS.open("a", encoding="utf-8") as archivo:
        archivo.write(f"{usuario}:{hash_guardado}\n")

    print("Usuario registrado")
    return True

Se normaliza el nombre, se comprueba duplicidad y se valida una longitud mínima. Esta validación es básica; una política real debe adaptarse al contexto y evitar reglas arbitrarias que perjudiquen contraseñas largas.

Ocultar la contraseña en el terminal

El módulo getpass permite leer una contraseña sin mostrarla:

from getpass import getpass

usuario = input("Usuario: ")
contrasena = getpass("Contraseña: ")

Consulta la guía de lectura segura de contraseñas en el terminal para conocer limitaciones y manejo de errores.

Validar el login

import hmac

def iniciar_sesion(usuario: str, contrasena: str) -> bool:
    usuarios = cargar_usuarios()
    usuario = usuario.strip().lower()
    hash_guardado = usuarios.get(usuario)

    if hash_guardado is None:
        return False

    hash_recibido = crear_hash(contrasena)
    return hmac.compare_digest(hash_guardado, hash_recibido)

compare_digest realiza una comparación diseñada para reducir diferencias de tiempo observables. En una aplicación educativa local es una buena práctica, aunque no convierte el sistema en una solución de producción.

def menu():
    while True:
        print("\n1. Registrar")
        print("2. Iniciar sesión")
        print("3. Salir")
        opcion = input("Elige una opción: ").strip()

        if opcion == "1":
            usuario = input("Nuevo usuario: ")
            contrasena = getpass("Nueva contraseña: ")
            registrar_usuario(usuario, contrasena)
        elif opcion == "2":
            usuario = input("Usuario: ")
            contrasena = getpass("Contraseña: ")
            if iniciar_sesion(usuario, contrasena):
                print("Acceso concedido")
            else:
                print("Credenciales incorrectas")
        elif opcion == "3":
            break
        else:
            print("Opción inválida")

El mensaje de error no revela si falló el usuario o la contraseña. Esta práctica evita facilitar la enumeración de cuentas.

Usar salt con PBKDF2

Para mejorar el ejercicio, genera un salt aleatorio y utiliza PBKDF2:

import hashlib
import secrets

ITERACIONES = 600_000

def crear_registro(contrasena: str) -> tuple[str, str]:
    salt = secrets.token_bytes(16)
    derivado = hashlib.pbkdf2_hmac(
        "sha256",
        contrasena.encode("utf-8"),
        salt,
        ITERACIONES,
    )
    return salt.hex(), derivado.hex()

La documentación oficial de secrets explica cómo generar valores criptográficamente seguros. Cada usuario debe tener un salt diferente.

Formato con salt

El archivo podría almacenar:

usuario:salt_hex:hash_hex

Al iniciar sesión, se recupera el salt, se deriva nuevamente la clave con las mismas iteraciones y se compara el resultado.

Evitar inyección de líneas

No permitas caracteres como dos puntos o saltos de línea en el nombre de usuario:

def usuario_valido(usuario: str) -> bool:
    return bool(usuario) and ":" not in usuario and "\n" not in usuario

También puede usarse una expresión regular para aceptar únicamente letras, números, guion y guion bajo.

Concurrencia y corrupción del archivo

Dos procesos que escriben al mismo tiempo pueden corromper el archivo o registrar duplicados. Un TXT no ofrece transacciones ni bloqueo robusto. Para aplicaciones con múltiples usuarios, utiliza una base de datos con restricciones únicas y operaciones atómicas.

Pruebas del sistema

Prueba registro correcto, usuario vacío, duplicados, contraseña corta, credenciales válidas, contraseña incorrecta, archivo inexistente y líneas dañadas. La guía de pruebas unitarias en Python ayuda a automatizar estos casos.

Variables y secretos

Si el proyecto evoluciona, no guardes configuraciones sensibles directamente en el código. Revisa cómo leer variables de entorno en Python.

Cuándo abandonar el archivo TXT

Utiliza una base de datos y un framework de autenticación cuando necesites recuperación de contraseña, sesiones, bloqueo de intentos, auditoría, permisos, múltiples procesos o exposición en Internet. No construyas autenticación crítica desde cero si existe una solución mantenida.

Conclusión

Un login con archivos TXT es un excelente ejercicio para practicar funciones, archivos, diccionarios, hashes y validación. Su valor está en el aprendizaje, no en la seguridad de producción. Mantén la advertencia visible, utiliza hashes con salt en la versión educativa y migra a componentes especializados cuando el proyecto deje de ser una demostración local.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Projeto clássico do jogo Pong desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear el juego Pong en Python con Turtle

    Crea un juego Pong en Python con Turtle: ventana, paletas, pelota, teclado, colisiones, marcador, velocidad y código completo.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Criação de jogos para iniciantes usando Pygame em Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Pygame para principiantes: crea tu primer juego

    Aprende Pygame desde cero: instalación, ventana, eventos, movimiento, delta time, colisiones, puntuación, imágenes, sonido y sprites.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Ilustração de uma cobra com o logo do Python centralizado
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear el juego Snake en Python con Turtle

    Crea el juego Snake en Python con Turtle: movimiento, comida, crecimiento, puntuación, colisiones, controles y mejoras de dificultad.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Chatbot simples em Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un chatbot simple con Python

    Crea un chatbot simple con Python usando reglas, normalización de texto, intents, JSON, memoria temporal, pruebas y una arquitectura reutilizable.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Criptografia e segurança de dados em Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un generador de contraseñas seguro en Python

    Crea un generador de contraseñas seguro en Python con secrets, reglas configurables, CLI, validación, passphrases y pruebas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Jogo da forca para iniciantes desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un juego del ahorcado en Python

    Crea un juego del ahorcado en Python con palabras aleatorias, validación, letras repetidas, vidas, dibujos ASCII, pistas y opción de

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026