Hello everyone
Am getting stumped on trying to implement a multi-user login solution using Pyrebase.
I have a working copy of the code for a single-user password-protected login, unfortunately am unable to implement a multi-user password-protected login using Pyrebase.
I organized my code as follows:
main.py
: A list of Streamlit apps/pages in the sidebar for users to navigate
import streams
import streamlit as st
def main():
PAGES = {
"Stream One": streams.one,
"Stream Two": streams.two,
"Stream Three": streams.three
}
st.sidebar.title("My Streamlit App")
selection = st.sidebar.radio("Go to", list(PAGES.keys()))
PAGES[selection].write()
streams.one,two,three are .py
files that contain a .write()
method that are stand-alone Streamlit scripts.
multi_user_auth.py
: Authenticates the user before allowing view access to the pages in main.py
import streams
import pyrebase
import streamlit as st
from streams.main import main
def authenticate():
# Configuration Key
firebaseConfig = {
...
};
# Firebase Authentication
firebase = pyrebase.initialize_app(firebaseConfig)
auth = firebase.auth()
# Database
db = firebase.database()
storage = firebase.storage()
# Authentication
choice_block = st.empty()
choice = choice_block.radio('Login / Signup', ['Login', 'Sign up'])
# E-mail input
email_block = st.empty()
email = email_block.text_input('Please enter your email address')
# Password input
password_block = st.empty()
password = password_block.text_input('Please enter your password',type = 'password')
# Sign up block
if choice == 'Sign up':
username_block = st.empty()
username = username_block.text_input('Please input your app user name', value='Default')
sign_up_block = st.empty()
sign_up = sign_up_block.button('Sign Up')
if sign_up:
try:
user = auth.create_user_with_email_and_password(email, password)
st.success('Your account was created successfully!')
# Sign in
user = auth.sign_in_with_email_and_password(email, password)
db.child(user['localId']).child("Username").set(username)
db.child(user['localId']).child("ID").set(user['localId'])
st.info(f"Welcome {username}, you can now login to the system.")
sign_up_block.empty()
except:
st.error('Account already exists!')
# Login block
elif choice == 'Login':
# Login button
login_block = st.empty()
login = login_block.button('Login')
if login:
user = auth.sign_in_with_email_and_password(email,password)
while user:
username = db.child(user['localId']).child("Username").get().val()
st.sidebar.title(f"Welcome {username}!")
# Delete all placeholders
choice_block.empty()
email_block.empty()
password_block.empty()
login_block.empty()
# Display all pages to the user for navigation
main()
if __name__ == "__main__":
authenticate()
After the user signs up and logs in, all pages defined in main.py
display successfully in the sidebar.
However, if the user clicks on any of the other pages in the sidebar, instead of calling the write()
method on that particular page, Streamlit re-directs to the login page again, forcing the user to re-input their login details.
Is there any way to preserve / persist session state such that the user can navigate through the multiple pages in the sidebar once logged in?
I managed to get this behavior working using st.session_state
and a single password input (script below), but this does not cater to the desired outcome of multi-user password login.
single_password_auth.py
: Controls access to pages using a single password, but cannot cater to multi-user login
import streamlit as st
from streams.main import main
def authenticate():
# Initialize an empty session state variable
if 'password' not in st.session_state:
st.session_state['password'] = ''
# Check if password matches input
if st.session_state.password != 'SuperSecretPassword!':
login_block = st.empty()
password = login_block.text_input('Please enter the password:', value='', type='password')
st.session_state.password = password
if st.session_state.password == 'SuperSecretPassword!':
# Remove title after user has logged in
login_block.empty()
title.empty()
main()
elif password:
st.error("Please enter a valid password")
else:
title.empty()
main()
if __name__ == "__main__":
authenticate(main)