You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Streamlit应用登录按钮需点击两次才能登录问题求助

Streamlit登录按钮需点击两次才能生效的问题修复

问题根源

  1. Streamlit全脚本重运行机制:每次交互(比如点击按钮)都会重新执行整个脚本。首次点击登录按钮时,st.session_state.user被设置,但此时当前脚本的执行流程已经走到login()函数内部,main()开头的登录状态判断不会重新触发,必须等下一次页面刷新(第二次点击按钮)才会检测到用户已登录。
  2. 冗余的轮询逻辑:login()里的while循环+time.sleep(1)完全没必要,会阻塞线程,延迟状态更新的生效时间。
  3. 无用的自定义SessionState类:Streamlit原生已经提供st.session_state,自定义类未被使用,属于冗余代码。

修复方案

修改步骤

  1. 移除冗余的SessionState类,直接使用Streamlit原生状态管理
  2. 删除login()中不必要的轮询逻辑,同步执行认证即可
  3. 在登录成功设置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:14:58