如何在Streamlit应用中保存用户信息并实现刷新保持登录状态
Streamlit 实现页面刷新后保持登录状态的方案
用Cookie实现页面刷新后保持登录完全可行,这是Web应用中实现持久化会话的标准方案之一。下面是具体的实现思路和代码示例:
核心思路
- 登录成功后生成会话令牌:用户登录验证通过后,生成一个唯一且不可伪造的会话令牌,将令牌存入Cookie,同时在数据库中记录令牌对应的用户ID和过期时间。
- 页面加载时验证令牌:每次页面刷新或打开新会话时,先读取Cookie中的令牌,验证其在数据库中是否存在且未过期,验证通过则自动登录用户。
代码实现
首先需要安装Cookie管理依赖:
pip install streamlit-cookie-manager
然后编写核心逻辑:
import streamlit as st from streamlit_cookie_manager import CookieManager import uuid import datetime import sqlite3 import bcrypt # 用于密码哈希,注册环节需同步使用该工具加密密码 # 初始化Cookie管理器 cookie_manager = CookieManager() # 连接数据库(假设已存在users表,包含id、name、hashed_password字段) conn = sqlite3.connect('school_app.db') c = conn.cursor() # 确保sessions表存在,用于存储会话令牌 c.execute(''' CREATE TABLE IF NOT EXISTS sessions ( token TEXT PRIMARY KEY, user_id INTEGER, expires_at TEXT, FOREIGN KEY(user_id) REFERENCES users(id) ) ''') conn.commit() def validate_session_token(token): """验证会话令牌是否有效""" c.execute('SELECT user_id, expires_at FROM sessions WHERE token = ?', (token,)) session = c.fetchone() if not session: return None user_id, expires_at_str = session expires_at = datetime.datetime.fromisoformat(expires_at_str) if datetime.datetime.now() > expires_at: # 令牌过期,清理无效会话 c.execute('DELETE FROM sessions WHERE token = ?', (token,)) conn.commit() return None return user_id def create_new_session(user_id): """为用户创建新的会话令牌""" # 先删除用户已有会话,避免多端登录(可选逻辑) c.execute('DELETE FROM sessions WHERE user_id = ?', (user_id,)) token = str(uuid.uuid4()) # 生成唯一随机令牌 expires_at = datetime.datetime.now() + datetime.timedelta(days=7) # 设置7天过期 c.execute('INSERT INTO sessions (token, user_id, expires_at) VALUES (?, ?, ?)', (token, user_id, expires_at.isoformat())) conn.commit() return token, expires_at # 页面初始化时检查会话状态 current_user = None token = cookie_manager.get('session_token') if token: user_id = validate_session_token(token) if user_id: # 获取当前用户信息 c.execute('SELECT name FROM users WHERE id = ?', (user_id,)) current_user = c.fetchone()[0] # 根据登录状态渲染对应页面 if not current_user: st.title('用户登录') name = st.text_input('姓名') password = st.text_input('密码', type='password') if st.button('登录'): # 验证用户密码(数据库中存储的是哈希后的密码) c.execute('SELECT id, hashed_password FROM users WHERE name = ?', (name,)) user = c.fetchone() if user: user_id, hashed_pw = user if bcrypt.checkpw(password.encode('utf-8'), hashed_pw): # 登录成功,创建会话并设置Cookie token, expires_at = create_new_session(user_id) cookie_manager.set('session_token', token, expires_at=expires_at, httponly=True) st.rerun() else: st.error('密码错误') else: st.error('用户不存在') else: st.title(f'欢迎回来,{current_user}!') if st.button('退出登录'): # 清理Cookie和数据库中的会话记录 cookie_manager.delete('session_token') c.execute('DELETE FROM sessions WHERE user_id = ?', (user_id,)) conn.commit() st.rerun() conn.close()
关键注意事项
- 密码安全:绝对不能明文存储密码,注册用户时必须用
bcrypt这类哈希算法加密后再存入数据库。 - 令牌安全性:使用UUID生成随机令牌,避免被恶意猜测;开启Cookie的
httponly属性,防止XSS攻击窃取Cookie内容。 - 令牌过期:设置合理的过期时间,过期后自动清理数据库中的无效会话,避免资源浪费。
- HTTPS部署:如果应用部署在公网环境,一定要启用HTTPS,并开启Cookie的
secure属性,确保Cookie仅通过加密通道传输。
内容的提问来源于stack exchange,提问作者Daniel Phillion
相关产品推荐
相关产品推荐

