Streamlit应用登录按钮需点击两次才能登录问题求助
Streamlit登录按钮需点击两次才能生效的问题修复
问题根源
- Streamlit全脚本重运行机制:每次交互(比如点击按钮)都会重新执行整个脚本。首次点击登录按钮时,
st.session_state.user被设置,但此时当前脚本的执行流程已经走到login()函数内部,main()开头的登录状态判断不会重新触发,必须等下一次页面刷新(第二次点击按钮)才会检测到用户已登录。 - 冗余的轮询逻辑:
login()里的while循环+time.sleep(1)完全没必要,会阻塞线程,延迟状态更新的生效时间。 - 无用的自定义SessionState类:Streamlit原生已经提供
st.session_state,自定义类未被使用,属于冗余代码。
修复方案
修改步骤
- 移除冗余的
SessionState类,直接使用Streamlit原生状态管理 - 删除
login()中不必要的轮询逻辑,同步执行认证即可 - 在登录成功设置
st.session_state.user后,调用st.rerun()(Streamlit 1.21.0+支持)立即触发页面重渲染,让main()函数实时检测到登录状态
修改后的完整代码
import streamlit as st import mysql.connector import configparser import hashlib # 密码哈希函数 def hash_password(password): salt = hashlib.sha256(str.encode(password)).hexdigest()[:10] hashed_password = hashlib.sha256(str.encode(salt + password)).hexdigest() + ':' + salt return hashed_password # 密码校验函数 def check_password(password, hashed_password): try: stored_password, salt = hashed_password.split(':') except ValueError: return False return stored_password == hashlib.sha256(str.encode(salt + password)).hexdigest() # 用户认证函数 def authenticate(email, password): cursor = mydb.cursor() query = "SELECT email, password FROM users WHERE email=%s" cursor.execute(query, (email,)) result = cursor.fetchone() cursor.close() if result: stored_email, stored_password = result if check_password(password, stored_password): return stored_email return False # 创建用户函数 def create_user(name, email, password): cursor = mydb.cursor() hashed_password = hash_password(password) query = "INSERT INTO users (name, email, password) VALUES (%s, %s, %s)" cursor.execute(query, (name, email, hashed_password)) mydb.commit() user_id = cursor.lastrowid cursor.close() return user_id # 读取数据库配置 config = configparser.ConfigParser() config.read('config.ini') database_user = config.get('database', 'user') database_password = config.get('database', 'password') database_host = config.get('database', 'host') database_name = config.get('database', 'database') # 连接数据库 mydb = mysql.connector.connect(user=database_user, password=database_password, host=database_host, database=database_name) # 页面配置 st.set_page_config(page_title="Chitti 2.0", page_icon=":guardsman:", layout="wide") # 登录页面 def login(): st.markdown("<h1 style='text-align: center;'>Login</h1>", unsafe_allow_html=True) email = st.text_input("Email") password = st.text_input("Password", type="password") st.write('<style>div.row-widget.stButton > button {width: 100%;}</style>', unsafe_allow_html=True) if st.button("Login"): if email and password: with st.spinner('Logging in...'): user = authenticate(email, password) if user: st.session_state.user = user st.success("Logged in successfully!") st.rerun() # 立即触发页面重渲染 else: st.error("Invalid email or password") # 注册页面 def signup(): st.header("Sign Up") name = st.text_input("Name") email = st.text_input("Email", key="signup_email") password = st.text_input("Password", type="password") confirm_password = st.text_input("Confirm Password", type="password") if password != confirm_password: st.error("Passwords do not match") elif st.button("Sign Up"): if name and email and password: create_user(name, email, password) st.success("User created successfully!") else: st.error("Please fill in all fields") # 登出函数 def logout(): st.session_state.pop("user", None) st.success("Logged out successfully") st.rerun() # 主逻辑 def main(): if "user" not in st.session_state: # 登录/注册标签切换 tab1, tab2 = st.tabs(["Login", "Sign Up"]) with tab1: login() with tab2: signup() return # 已登录状态 st.write(f"Welcome, {st.session_state.user}!") st.write("Main APP") if st.button("Logout"): logout() if __name__ == '__main__': main()
额外优化
- 新增登录失败错误提示,提升用户体验
- 数据库操作后关闭游标,避免资源泄漏
- 注册页面增加必填字段校验
- 添加登录/注册标签页切换,优化交互流程
内容的提问来源于stack exchange,提问作者Pemula Saketh
相关产品推荐
相关产品推荐

