提问人:Luis Valencia 提问时间:11/6/2023 更新时间:11/21/2023 访问量:139
如何在 Streamlit 中的多页应用程序中保留会话状态变量
How to keep session state variables across a multipage app in Streamlit
问:
我的应用有几个页面,第一次加载时,它会检测会话状态中是否有访问令牌,如果没有用户单击登录名转到 Azure Id,然后在查询参数中返回代码,然后检索访问令牌。 然后我可以根据用户组等来渲染一些按钮。
这在我的主页上工作得很好。
Security.py
# Initialize the MSAL ConfidentialClientApplication
app = msal.ConfidentialClientApplication(CLIENT_ID, authority=AUTHORITY, client_credential=CLIENT_SECRET)
# Function to get the authorization URL
def get_auth_url():
"""
Generate the authorization URL for user sign-in.
"""
auth_url = app.get_authorization_request_url(SCOPE, redirect_uri=REDIRECT_URI)
return auth_url
# Function to exchange authorization code for an access token
def get_token_from_code(auth_code):
"""
Exchange an authorization code for an access token.
"""
result = app.acquire_token_by_authorization_code(auth_code, scopes=SCOPE, redirect_uri=REDIRECT_URI)
return result['access_token']
# Function to get user information
def get_user_info(access_token):
"""
Get user information using the provided access token.
"""
headers = {'Authorization': f'Bearer {access_token}'}
response = requests.get('https://graph.microsoft.com/v1.0/me', headers=headers)
return response.json()
# Function to get user's groups with display names
def get_user_groups(access_token):
"""
Get the user's groups with display names using the provided access token.
"""
headers = {'Authorization': f'Bearer {access_token}'}
params = {
'$select': 'displayName, id', # Specify the fields you want to retrieve
}
response = requests.get('https://graph.microsoft.com/v1.0/me/memberOf', headers=headers, params=params)
return response.json()
# Function to handle the OAuth2 redirect flow
def handle_redirect():
"""
Handle the OAuth2 redirect flow, retrieve the access token, and store it in the session.
"""
if not st.session_state.get('access_token'):
code = st.experimental_get_query_params().get('code')
if code:
access_token = get_token_from_code(code)
st.session_state['access_token'] = access_token
st.experimental_set_query_params()
那么 utils.py 有这个:
def setup_page(): 如果 st.experimental_get_query_params().get('code'): # 如果存在授权代码,则处理 OAuth2 重定向 handle_redirect() access_token = st.session_state.get('access_token')
if access_token:
# If an access token is available, retrieve and display user information and groups
user_info = get_user_info(access_token)
st.session_state['user_info'] = user_info
# Get user's group information
user_groups = get_user_groups(access_token)
st.session_state['user_groups'] = user_groups
# Display user's group information, handling cases where 'displayName' is not available
# if 'value' in user_groups:
# for group in user_groups['value']:
# group_display_name = group.get('displayName', group.get('mailNickname', group["id"]))
# group_id = group["id"]
# st.write(group_id)
# return True
else:
# If there's no access token, prompt the user to sign in
st.write("Please sign-in to use this app.")
auth_url = get_auth_url()
st.markdown(f"<a href='{auth_url}' target='_self'>Sign In</a>", unsafe_allow_html=True)
st.stop()
然后在我的主页和 page1.py 上,page2.py 我只是打电话给setup_page。
但是,当我从主页转到第 1 页时,session_state丢失了,访问令牌不再存在。
是什么原因造成的?
答:
Streamlit 的session_state旨在在重新运行脚本时保持特定于会话的状态。但是,它并非旨在跨不同的页面或应用实例保留。当您在 Streamlit 中从一个页面导航到另一个页面时,每个页面本质上都是脚本的单独实例。
在本例中,当您从主页移动到 page1 时,将重新执行 page1 的脚本,并重置session_state。若要跨不同页面维护状态,可以考虑使用其他方法,例如通过 URL 传递参数、在数据库中存储信息或使用全局变量。
下面是一个高级建议:
- 通过 URL 传递访问令牌 参数:
将用户重定向到 page1 时,将访问令牌作为参数附加到 URL 中。 在 page1 中,读取 URL 参数并使用访问令牌。
例:
# Redirect from homepage
page1_url = f"/page1?access_token={access_token}"
st.markdown(f"<a href='{page1_url}'>Go to Page 1</a>", unsafe_allow_html=True)
# In page1.py
access_token = st.experimental_get_query_params().get('access_token')
- 将访问令牌存储在数据库或外部存储中:
将访问令牌存储在数据库或外部存储中(考虑安全隐患)。 根据用户的会话在每个页面中检索访问令牌。
例:
# Store access token
st.session_state['access_token'] = access_token
# Retrieve access token in page1
access_token = st.session_state.get('access_token')
选择适合应用程序要求和安全注意事项的方法。在 URL 中传递敏感信息或将其存储在外部存储中时,请注意安全性。
快乐学习!!
评论