| |
| """ |
| login.py — Sistema de autenticação seguro para Streamlit |
| Compatível com HuggingFace Spaces (Linux) e Windows. |
| |
| Recursos: |
| - Login normal (usuários no banco SQLite/Postgres/MySQL) |
| - Hash seguro com bcrypt |
| - Autologin para testes (DISABLE_AUTH=1) |
| - Login emergencial (ALLOW_EMERGENCY_LOGIN=1 + EMERG_USER + EMERG_PASS_BCRYPT) |
| - Auditoria opcional via registrar_log |
| """ |
|
|
| import os |
| import bcrypt |
| import streamlit as st |
|
|
| |
| try: |
| from utils_auditoria import registrar_log |
| _HAS_AUDIT = True |
| except Exception: |
| _HAS_AUDIT = False |
|
|
| |
| from banco import SessionLocal |
| from models import Usuario |
|
|
| |
| _DISABLE_AUTH = os.getenv("DISABLE_AUTH", "0") == "1" |
| _ALLOW_EMERG = os.getenv("ALLOW_EMERGENCY_LOGIN", "0") == "1" |
|
|
| _DEMO_USER = os.getenv("DEMO_USER", "demo") |
| _DEMO_PERFIL = os.getenv("DEMO_PERFIL", "admin") |
| _DEMO_EMAIL = os.getenv("DEMO_EMAIL", "demo@example.com") |
|
|
|
|
| |
| |
| |
| def verificar_hash(senha_digitada: str, senha_hash: str) -> bool: |
| """Retorna True se a senha confere com o hash bcrypt.""" |
| try: |
| return bcrypt.checkpw( |
| senha_digitada.encode("utf-8"), |
| senha_hash.encode("utf-8") |
| ) |
| except Exception: |
| return False |
|
|
|
|
| |
| |
| |
| def _autologin_if_allowed() -> bool: |
| if not _DISABLE_AUTH: |
| return False |
|
|
| st.session_state.logado = True |
| st.session_state.usuario = _DEMO_USER |
| st.session_state.perfil = _DEMO_PERFIL |
| st.session_state.email = _DEMO_EMAIL |
|
|
| if _HAS_AUDIT: |
| try: |
| registrar_log( |
| usuario=_DEMO_USER, |
| acao="Autologin (DISABLE_AUTH=1)", |
| tabela="login", |
| registro_id=None |
| ) |
| except Exception: |
| pass |
|
|
| st.success(f"🔓 Autologin ativo: {_DEMO_USER} ({_DEMO_PERFIL})") |
| return True |
|
|
|
|
| |
| |
| |
| def _try_emergency_login(usuario: str, senha: str) -> bool: |
| if not _ALLOW_EMERG: |
| return False |
|
|
| EMU = os.getenv("EMERG_USER") |
| EHP = os.getenv("EMERG_PASS_BCRYPT") |
|
|
| if not EMU or not EHP: |
| return False |
|
|
| if usuario.strip().lower() != EMU.strip().lower(): |
| return False |
|
|
| if not verificar_hash(senha, EHP): |
| return False |
|
|
| st.session_state.logado = True |
| st.session_state.usuario = EMU |
| st.session_state.perfil = "admin" |
| st.session_state.email = f"{EMU}@local" |
|
|
| st.success("🔑 Login emergencial bem-sucedido.") |
|
|
| if _HAS_AUDIT: |
| try: |
| registrar_log( |
| usuario=EMU, |
| acao="Login emergencial", |
| tabela="login", |
| registro_id=None |
| ) |
| except Exception: |
| pass |
|
|
| return True |
|
|
|
|
| |
| |
| |
| def _login_normal(usuario: str, senha: str) -> bool: |
| db = SessionLocal() |
| try: |
| row = ( |
| db.query(Usuario) |
| .filter(Usuario.usuario == usuario.strip()) |
| .first() |
| ) |
| except Exception: |
| row = None |
| finally: |
| try: |
| db.close() |
| except Exception: |
| pass |
|
|
| if not row: |
| return False |
|
|
| if not verificar_hash(senha, row.senha_hash): |
| return False |
|
|
| |
| st.session_state.logado = True |
| st.session_state.usuario = row.usuario |
| st.session_state.perfil = row.perfil |
| st.session_state.email = row.email |
|
|
| if _HAS_AUDIT: |
| try: |
| registrar_log( |
| usuario=row.usuario, |
| acao="Login normal", |
| tabela="login", |
| registro_id=row.id |
| ) |
| except Exception: |
| pass |
|
|
| return True |
|
|
|
|
| |
| |
| |
| def login(): |
| |
| if _autologin_if_allowed(): |
| return |
|
|
| st.markdown("### 🔐 Login") |
| with st.form("form_login"): |
| usuario = st.text_input("Usuário") |
| senha = st.text_input("Senha", type="password") |
| btn = st.form_submit_button("Entrar") |
|
|
| if btn: |
| usuario = usuario.strip() |
| senha = senha.strip() |
|
|
| |
| if _login_normal(usuario, senha): |
| st.rerun() |
| return |
|
|
| |
| if _try_emergency_login(usuario, senha): |
| st.rerun() |
| return |
|
|
| st.error("Usuário ou senha incorretos.") |
|
|
| |
| if _ALLOW_EMERG: |
| st.info("🔑 Login emergencial disponível.") |
|
|
|
|
| |
| |
| |
| def logout(): |
| st.session_state.logado = False |
| st.session_state.usuario = None |
| st.session_state.perfil = None |
| st.session_state.email = None |
| st.rerun() |