Login funcionando

This commit is contained in:
LS
2025-03-24 14:50:42 -03:00
parent cccca2ef29
commit 0f4056fbff
5 changed files with 203 additions and 117 deletions

75
app.py
View File

@@ -37,7 +37,7 @@ def login_required(f):
def decorated_function(*args, **kwargs):
if 'user_id' not in session:
flash('Por favor, faça login para acessar esta página.', 'warning')
return redirect(url_for('login', next=request.url))
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated_function
@@ -59,16 +59,35 @@ def login():
password = request.form.get("password")
otp = request.form.get("otp")
# Log dos dados recebidos (sem a senha)
print(f"Tentativa de login - Username: {username}, OTP fornecido: {'Sim' if otp else 'Não'}")
user = db_session.query(Usuario).filter_by(username=username).first()
if user and user.check_password(password) and user.verify_otp(otp):
session['user_id'] = user.id # Usando a sessão do Flask
session['is_admin'] = user.is_admin
next_page = request.args.get('next')
flash('Login realizado com sucesso!', 'success')
return redirect(next_page or url_for('home'))
else:
flash('Credenciais inválidas', 'danger')
if not user:
print(f"Erro: Usuário '{username}' não encontrado")
flash('Usuário não encontrado', 'danger')
return render_template('login.html')
if not user.check_password(password):
print(f"Erro: Senha incorreta para o usuário '{username}'")
flash('Senha incorreta', 'danger')
return render_template('login.html')
if not user.verify_otp(otp):
print(f"Erro: Código OTP inválido para o usuário '{username}'")
print(f"OTP fornecido: {otp}")
print(f"OTP secret do usuário: {user.otp_secret}")
flash('Código OTP inválido', 'danger')
return render_template('login.html')
# Se chegou aqui, login bem sucedido
print(f"Login bem sucedido para o usuário '{username}'")
session['user_id'] = user.id
session['is_admin'] = user.is_admin
next_page = request.args.get('next')
flash('Login realizado com sucesso!', 'success')
return redirect(next_page or url_for('home'))
return render_template('login.html')
@@ -84,14 +103,36 @@ def logout():
@login_required
def home():
"""Página inicial do sistema"""
links = []
for rule in app.url_map.iter_rules():
if "GET" in rule.methods and has_no_empty_params(rule):
url = url_for(rule.endpoint, **(rule.defaults or {}))
endpoint_name = 'Início' if rule.endpoint == 'home' else rule.endpoint
links.append((url, endpoint_name))
return render_template('home.html', links=links)
try:
links = []
# Filtrar apenas as rotas que queremos mostrar
allowed_endpoints = {
'listar_militantes': 'Militantes',
'listar_cotas': 'Cotas',
'listar_pagamentos': 'Pagamentos',
'listar_materiais': 'Materiais',
'listar_vendas_jornal': 'Vendas de Jornal',
'listar_assinaturas': 'Assinaturas'
}
for rule in app.url_map.iter_rules():
if (rule.endpoint in allowed_endpoints and
"GET" in rule.methods and
len(rule.arguments) == 0): # Apenas rotas sem parâmetros
url = url_for(rule.endpoint)
nome = allowed_endpoints[rule.endpoint]
links.append((url, nome))
# Ordenar links pelo nome
links.sort(key=lambda x: x[1])
return render_template('home.html', links=links)
except Exception as e:
print(f"Erro na página inicial: {e}")
import traceback
traceback.print_exc()
flash('Erro ao carregar a página inicial', 'error')
return render_template('home.html', links=[])
# Rota para criar um novo militante
@app.route("/militantes/novo", methods=["GET", "POST"])

View File

@@ -1,78 +1,61 @@
from functions.database import Usuario, Base, engine, get_db_connection
from functions.database import init_database, Usuario, get_db_connection
import qrcode
import os
from pathlib import Path
def create_admin_user():
try:
# Criar as tabelas se não existirem
Base.metadata.create_all(engine)
# Inicializar o banco de dados
init_database()
# Obter conexão com o banco
# Obter a sessão
db_session = get_db_connection()
# Verificar se já existe um admin
# Verificar se o admin foi criado
admin = db_session.query(Usuario).filter_by(username="admin").first()
if not admin:
# Criar usuário admin
admin = Usuario(
username="admin",
password="admin123",
is_admin=True
)
admin.email = "admin@example.com"
if admin:
print("\n=== Detalhes do Usuário Admin ===")
print(f"Username: admin")
print(f"Email: {admin.email}")
print(f"OTP Secret: {admin.otp_secret}")
db_session.add(admin)
db_session.commit()
# Configurar diretório para o QR Code
home = Path.home()
qr_dir = home / '.local' / 'share' / 'controles' / 'qrcodes'
qr_dir.mkdir(parents=True, exist_ok=True)
print("\n=== Usuário Admin Criado com Sucesso ===")
# Gerar QR Code
qr = qrcode.QRCode(version=1, box_size=10, border=5)
qr.add_data(admin.get_otp_uri())
qr.make(fit=True)
# Salvar QR Code
qr_path = qr_dir / 'admin_qr.png'
img = qr.make_image(fill_color="black", back_color="white")
img.save(str(qr_path))
print(f"\nQR Code salvo em: {qr_path}")
print("\nPasso a passo para configurar o OTP:")
print("1. Instale um aplicativo autenticador no seu celular")
print(" (Google Authenticator, Microsoft Authenticator, etc)")
print("2. Abra o aplicativo")
print("3. Selecione a opção para adicionar uma nova conta")
print("4. Escaneie o QR Code gerado")
print("\nOU, se preferir configuração manual:")
print(f"1. Use o segredo: {admin.otp_secret}")
print("2. Nome da conta: admin")
print("3. Tipo: Baseado em tempo (TOTP)")
else:
print("\n=== Usuário Admin Encontrado ===")
print(f"Username: admin")
print(f"Senha: admin123")
print(f"Segredo OTP: {admin.otp_secret}")
# Gerar QR Code
qr = qrcode.QRCode(version=1, box_size=10, border=5)
qr.add_data(admin.get_otp_uri())
qr.make(fit=True)
# Encontrar o diretório raiz do projeto (onde está o app.py)
current_dir = Path(__file__).resolve().parent
project_root = current_dir.parent # Volta um nível para a raiz do projeto
static_dir = project_root / 'static'
# Criar diretório static se não existir
os.makedirs(static_dir, exist_ok=True)
# Caminho completo para o arquivo QR code
qr_path = static_dir / 'admin_qr.png'
# Salvar QR Code como imagem
img = qr.make_image(fill_color="black", back_color="white")
img.save(str(qr_path))
print(f"\nQR Code salvo em: {qr_path}")
print(f"Diretório atual: {os.getcwd()}")
print(f"O arquivo existe? {os.path.exists(qr_path)}")
print("\nPasso a passo para configurar o OTP:")
print("1. Instale um aplicativo autenticador no seu celular")
print(" (Google Authenticator, Microsoft Authenticator, etc)")
print("2. Abra o aplicativo")
print("3. Selecione a opção para adicionar uma nova conta")
print("4. Escaneie o QR Code gerado")
print("\nOU, se preferir configuração manual:")
print(f"1. Use o segredo: {admin.otp_secret}")
print("2. Nome da conta: admin")
print("3. Tipo: Baseado em tempo (TOTP)")
print("ERRO: Falha ao criar usuário admin!")
except Exception as e:
print(f"\nErro durante a execução: {e}")
import traceback
traceback.print_exc()
finally:
if 'db_session' in locals():
db_session.close()
if __name__ == "__main__":
create_admin_user()

View File

@@ -4,16 +4,32 @@ from sqlalchemy.ext.declarative import declarative_base
from werkzeug.security import generate_password_hash, check_password_hash
import pyotp
import os
from pathlib import Path
from sqlalchemy.pool import NullPool
# Configurar caminho do banco de dados
db_dir = Path.home() / '.local' / 'share' / 'controles'
db_dir.mkdir(parents=True, exist_ok=True)
db_path = db_dir / 'database.db'
# Configurar engine com NullPool
engine = create_engine(
f'sqlite:///{db_path}',
echo=True,
poolclass=NullPool # Usar NullPool ao invés do pool padrão
)
Base = declarative_base()
engine = create_engine('sqlite:///database.db', echo=True)
SessionLocal = sessionmaker(bind=engine)
def get_db_connection():
"""
Retorna uma nova sessão do banco de dados
"""
return SessionLocal()
try:
return SessionLocal()
finally:
engine.dispose()
def execute_query(query, params=None):
"""
@@ -195,11 +211,17 @@ class Usuario(Base):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
result = check_password_hash(self.password_hash, password)
print(f"Verificação de senha para {self.username}: {'sucesso' if result else 'falha'}")
return result
def verify_otp(self, otp_code):
totp = pyotp.TOTP(self.otp_secret)
return totp.verify(otp_code)
result = totp.verify(otp_code)
print(f"Verificação OTP para {self.username}")
print(f"Código fornecido: {otp_code}")
print(f"Resultado da verificação: {'válido' if result else 'inválido'}")
return result
def get_otp_uri(self):
totp = pyotp.TOTP(self.otp_secret)
@@ -234,40 +256,61 @@ class RolePermissao(Base):
permissao = relationship("Permissao", back_populates="roles")
# Remover o banco de dados existente (se existir)
if os.path.exists('database.db'):
os.remove('database.db')
if os.path.exists(db_path):
os.remove(db_path)
# Criar todas as tabelas novamente
Base.metadata.create_all(engine)
# Criar roles iniciais
def create_initial_data():
session = get_db_connection()
def init_database():
"""Inicializa o banco de dados com dados básicos"""
print("Inicializando banco de dados...")
# Criar todas as tabelas
Base.metadata.create_all(engine)
session = SessionLocal()
try:
# Criar role de admin
admin_role = Role(nome="Administrador", nivel=1)
session.add(admin_role)
session.flush() # Para obter o ID da role
# Criar usuário admin
admin = Usuario(
username="admin",
password="admin123",
is_admin=True
)
admin.role_id = admin_role.id
session.add(admin)
session.commit()
print(f"Segredo OTP do admin: {admin.otp_secret}")
print("Usuário admin criado com sucesso!")
# Verificar se já existe um admin
admin = session.query(Usuario).filter_by(username="admin").first()
if not admin:
print("Criando role de administrador...")
# Criar role de admin
admin_role = session.query(Role).filter_by(nome="Administrador").first()
if not admin_role:
admin_role = Role(nome="Administrador", nivel=1)
session.add(admin_role)
session.commit()
print("Criando usuário admin...")
# Criar usuário admin
admin = Usuario(
username="admin",
password="admin123",
is_admin=True
)
admin.email = "admin@example.com"
admin.role_id = admin_role.id
session.add(admin)
session.commit()
print("=== Usuário Admin Criado ===")
print(f"Username: admin")
print(f"Senha: admin123")
print(f"Email: {admin.email}")
print(f"OTP Secret: {admin.otp_secret}")
else:
print("Usuário admin já existe")
except Exception as e:
print(f"Erro ao criar dados iniciais: {e}")
print(f"Erro na inicialização do banco: {e}")
session.rollback()
raise
finally:
session.close()
# Inicializar o banco de dados automaticamente quando o módulo for importado
init_database()
# Executar a criação dos dados iniciais
if __name__ == "__main__":
create_initial_data()
init_database()

View File

@@ -3,15 +3,26 @@
{% block title %}Início{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12">
<h2>Menu do Sistema</h2>
<div class="list-group">
{% for url, endpoint in links %}
<a href="{{ url }}" class="list-group-item list-group-item-action">
{{ endpoint|replace('_', ' ')|title }}
</a>
{% endfor %}
<div class="container">
<div class="row">
<div class="col-md-8 offset-md-2">
<h2 class="mb-4">Menu do Sistema</h2>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<div class="list-group">
{% for url, nome in links %}
<a href="{{ url }}" class="list-group-item list-group-item-action">
{{ nome }}
</a>
{% endfor %}
</div>
</div>
</div>
</div>

View File

@@ -14,7 +14,13 @@
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
<div class="alert alert-{{ category }}">
{{ message }}
{% if category == 'danger' %}
<br>
<small>Se o problema persistir, contate o administrador.</small>
{% endif %}
</div>
{% endfor %}
{% endif %}
{% endwith %}
@@ -22,7 +28,8 @@
<form method="POST">
<div class="mb-3">
<label for="username" class="form-label">Usuário</label>
<input type="text" class="form-control" id="username" name="username" required>
<input type="text" class="form-control" id="username" name="username" required
value="{{ request.form.username }}">
</div>
<div class="mb-3">
<label for="password" class="form-label">Senha</label>
@@ -30,7 +37,8 @@
</div>
<div class="mb-3">
<label for="otp" class="form-label">Código OTP</label>
<input type="text" class="form-control" id="otp" name="otp" required>
<input type="text" class="form-control" id="otp" name="otp" required
pattern="[0-9]{6}" title="Digite o código de 6 dígitos">
<small class="form-text text-muted">Digite o código de 6 dígitos do seu aplicativo autenticador</small>
</div>
<div class="d-grid">