Roudrigus commited on
Commit
d6d6963
·
verified ·
1 Parent(s): f23d6b2

Update login.py

Browse files
Files changed (1) hide show
  1. login.py +92 -12
login.py CHANGED
@@ -9,6 +9,7 @@ Recursos:
9
  - Autologin para testes (DISABLE_AUTH=1)
10
  - Login emergencial (ALLOW_EMERGENCY_LOGIN=1 + EMERG_USER + EMERG_PASS_BCRYPT)
11
  - Auditoria opcional via registrar_log
 
12
  """
13
 
14
  import os
@@ -34,6 +35,82 @@ _DEMO_USER = os.getenv("DEMO_USER", "demo")
34
  _DEMO_PERFIL = os.getenv("DEMO_PERFIL", "admin")
35
  _DEMO_EMAIL = os.getenv("DEMO_EMAIL", "demo@example.com")
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
  # =========================================================
39
  # 🛡️ HASH DE SENHAS
@@ -122,11 +199,7 @@ def _try_emergency_login(usuario: str, senha: str) -> bool:
122
  def _login_normal(usuario: str, senha: str) -> bool:
123
  db = SessionLocal()
124
  try:
125
- row = (
126
- db.query(Usuario)
127
- .filter(Usuario.usuario == usuario.strip())
128
- .first()
129
- )
130
  except Exception:
131
  row = None
132
  finally:
@@ -138,22 +211,29 @@ def _login_normal(usuario: str, senha: str) -> bool:
138
  if not row:
139
  return False
140
 
141
- if not verificar_hash(senha, row.senha_hash):
 
 
 
 
 
 
142
  return False
143
 
144
- # OK
 
145
  st.session_state.logado = True
146
- st.session_state.usuario = row.usuario
147
- st.session_state.perfil = row.perfil
148
- st.session_state.email = row.email
149
 
150
  if _HAS_AUDIT:
151
  try:
152
  registrar_log(
153
- usuario=row.usuario,
154
  acao="Login normal",
155
  tabela="login",
156
- registro_id=row.id
157
  )
158
  except Exception:
159
  pass
 
9
  - Autologin para testes (DISABLE_AUTH=1)
10
  - Login emergencial (ALLOW_EMERGENCY_LOGIN=1 + EMERG_USER + EMERG_PASS_BCRYPT)
11
  - Auditoria opcional via registrar_log
12
+ - Compatível com múltiplos nomes de coluna de senha (senha_hash, password_hash, senha, etc.)
13
  """
14
 
15
  import os
 
35
  _DEMO_PERFIL = os.getenv("DEMO_PERFIL", "admin")
36
  _DEMO_EMAIL = os.getenv("DEMO_EMAIL", "demo@example.com")
37
 
38
+ # ===== Helpers de compatibilidade com modelos diferentes =====
39
+ # Você pode forçar o(s) nome(s) da(s) coluna(s) de senha via Secrets:
40
+ # PASSWORD_FIELD=senha (ou lista: "senha,password_hash")
41
+ _PASSWORD_FIELDS_ENV = os.getenv("PASSWORD_FIELD", "").strip()
42
+ _PASSWORD_FIELDS = [f.strip() for f in _PASSWORD_FIELDS_ENV.split(",") if f.strip()]
43
+ # candidatos padrão, em ordem de preferência
44
+ _DEFAULT_PASS_FIELDS = ["senha_hash", "password_hash", "senha", "hash", "pass_hash", "pwd_hash"]
45
+
46
+ def _get_password_hash_from_row(row) -> str | None:
47
+ """Retorna o hash de senha a partir do objeto ORM 'row', testando vários nomes possíveis."""
48
+ # 1) Nomes vindos do ambiente, se houver
49
+ for fname in (_PASSWORD_FIELDS or []):
50
+ if hasattr(row, fname):
51
+ v = getattr(row, fname)
52
+ if v:
53
+ return str(v)
54
+
55
+ # 2) Nomes padrão
56
+ for fname in _DEFAULT_PASS_FIELDS:
57
+ if hasattr(row, fname):
58
+ v = getattr(row, fname)
59
+ if v:
60
+ return str(v)
61
+
62
+ # 3) Fallback: inspeciona __dict__ por chaves "parecidas"
63
+ try:
64
+ for k, v in getattr(row, "__dict__", {}).items():
65
+ if k.startswith("_"):
66
+ continue
67
+ if k.lower() in set(_DEFAULT_PASS_FIELDS):
68
+ if v:
69
+ return str(v)
70
+ except Exception:
71
+ pass
72
+
73
+ return None
74
+
75
+ def _get_user_identity_fields(row):
76
+ """
77
+ Retorna (usuario, perfil, email) com fallbacks para nomes alternativos.
78
+ """
79
+ usuario = (
80
+ getattr(row, "usuario", None)
81
+ or getattr(row, "username", None)
82
+ or getattr(row, "login", None)
83
+ or getattr(row, "nome_usuario", None)
84
+ )
85
+ perfil = (
86
+ getattr(row, "perfil", None)
87
+ or getattr(row, "role", None)
88
+ or getattr(row, "papel", None)
89
+ or "usuario"
90
+ )
91
+ email = (
92
+ getattr(row, "email", None)
93
+ or getattr(row, "e_mail", None)
94
+ or getattr(row, "mail", None)
95
+ )
96
+ return usuario, perfil, email
97
+
98
+ def _fetch_user_by_login(db, user_login: str):
99
+ """
100
+ Busca um usuário tentando múltiplas colunas de login, sem quebrar se alguma não existir.
101
+ Ordem: usuario, username, login, email.
102
+ """
103
+ candidates = ["usuario", "username", "login", "email"]
104
+ for field in candidates:
105
+ try:
106
+ col = getattr(Usuario, field)
107
+ row = db.query(Usuario).filter(col == user_login.strip()).first()
108
+ if row:
109
+ return row
110
+ except Exception:
111
+ continue
112
+ return None
113
+
114
 
115
  # =========================================================
116
  # 🛡️ HASH DE SENHAS
 
199
  def _login_normal(usuario: str, senha: str) -> bool:
200
  db = SessionLocal()
201
  try:
202
+ row = _fetch_user_by_login(db, usuario)
 
 
 
 
203
  except Exception:
204
  row = None
205
  finally:
 
211
  if not row:
212
  return False
213
 
214
+ # Obtém o hash de senha de forma robusta
215
+ pwd_hash = _get_password_hash_from_row(row)
216
+ if not pwd_hash:
217
+ # Sem hash → não conseguimos validar a senha
218
+ return False
219
+
220
+ if not verificar_hash(senha, pwd_hash):
221
  return False
222
 
223
+ # Preenche identidade do usuário com fallbacks
224
+ u, p, e = _get_user_identity_fields(row)
225
  st.session_state.logado = True
226
+ st.session_state.usuario = u or usuario
227
+ st.session_state.perfil = (p or "usuario").strip().lower()
228
+ st.session_state.email = e
229
 
230
  if _HAS_AUDIT:
231
  try:
232
  registrar_log(
233
+ usuario=st.session_state.usuario,
234
  acao="Login normal",
235
  tabela="login",
236
+ registro_id=getattr(row, "id", None)
237
  )
238
  except Exception:
239
  pass