Streamlit multi users

Can someone help me? I’ve created a Streamlit application with a login system, and it works fine. However, after deploying it to an AWS EC2 instance and restricting access to my IP address, I encounter an issue. When I access the app from my PC, everything works as expected. But when I try to access it from my mobile device using the same link, it allows access to the content that should be restricted to logged-in users. How can I ensure that each user has their own access and session?

What login system are you using?

Well, as it’s an application I’ve been working on and I don’t have much experience, if you could even help me to figure out if there are better ways, but I’ll share the code here so that you have an idea.

if not firebase_admin._apps:
cred = credentials.Certificate(‘sistema-de-gerenciamento-5bbc6-d5e47ad2003f.json’)
default_app = firebase_admin.initialize_app(cred)

db = firestore.client()

firebase = pyrebase.initialize_app(firebaseConfig)
auth_pyrebase = firebase.auth()
db_pyrebase = firebase.database()
storage = firebase.storage()

def is_valid_gmail(email):
return re.match(r"[^@]+@gmail.com$", email)

def is_valid_username(username):

return re.match(r"^[a-zA-Z0-9_-]+$", username)

def obter_informacoes_do_usuario(email):
usuario_limit = db.collection(“usuários”).stream()
for usuario in usuario_limit:
acesso_dict = usuario.to_dict()
if acesso_dict.get(‘email’) == email:
return acesso_dict
return None

def update_value():
st.session_state.value = “Logar”

def main():

login, register, forget_password = st.tabs(['Logar', 'Registrar Conta', 'Esqueci a senha'])
    
query_params = st.experimental_get_query_params()

if "login" not in st.session_state:
       
    st.session_state["login"] = query_params.get("login", ["False"])[0]

usuario_fez_login = False

st.experimental_set_query_params(login="False")

def login_app(): 
    
    email = st.text_input('Digite seu e-mail', key='login_email')
    senha = st.text_input('Digite sua senha', type='password', key='login_password')


    if st.button('Logar', on_click=update_value):

    
        if is_valid_gmail(email):
            

            try:
                user = auth_pyrebase.sign_in_with_email_and_password(email, senha)
                st.success('Logado com sucesso!')

                usuario_fez_login = True
                    
                acesso_dict = obter_informacoes_do_usuario(email)
                
                if usuario_fez_login:
                    if acesso_dict:
                        if acesso_dict.get('Tipo de acesso') == 'user':
                            st.markdown('VOCÊ NÃO TEM ACESSO')
                        elif acesso_dict.get('Tipo de acesso') == 'full_acess':
                                

                            st.session_state["login"] = "True"

                            st.experimental_set_query_params(login="True")

                            show_pages(pages)

                            url = "http://localhost:8501/?selected=full-acess"

                            webbrowser.open(url, new=0)

    
                        elif acesso_dict.get('Tipo de acesso') == 'mid_acess':
                            st.markdown('VOCÊ TEM ACESSO, PORÉM LIMITADO!')
                    else:
                        st.markdown('ERROR!')
                else:
                    st.write("Erro Estranho! Contate com o desenvolvedor")

            except Exception as e:
                usuario_fez_login = False
                st.experimental_set_query_params(login="False")
                st.error('Erro ao logar, verifique se cadastrou essa conta ou se não digitou seu e-mail e senha errados') 
        
        else:
            st.error("Tipo de e-mail inválido, use gmail por gentileza!")

def registrar_conta(nome_completo, nome_usuario, email, senha, senha2):

    if senha != senha2:
        st.error('As senhas não coincidem')

    if nome_completo is None or nome_completo.strip() == "":
        st.error('O campo do nome completo não pode ficar em branco')

    if not is_valid_username(nome_usuario):
        st.error('Nome de usuário inválido')
                    
    if not is_valid_gmail(email):
        st.warning('Digite um e-mail gmail por gentileza, exemplo: example@gmail.com')
                    
    if senha == senha2 and nome_completo.strip() != "" and is_valid_username(nome_usuario) and is_valid_gmail(email):
        try:
            user = auth_pyrebase.create_user_with_email_and_password(email, senha)
            user_uid = user['localId']
            user_obj = auth.get_user(user_uid)
            updated_user = auth.update_user(user_uid, display_name=nome_usuario)

            hashed_password = stauth.Hasher(senha).generate()

            user_data = {
                'nome completo': nome_completo,
                'email': email,
                'nome do usuário': nome_usuario,
                'senha': hashed_password,
                'Tipo de acesso': 'user'  
            }
                                
            users_collection = db.collection('usuários')
            users_collection.document(user_uid).set(user_data)

            st.success('Usuário registrado com sucesso')
            st.markdown('Agora use seu e-mail e senha para logar!')

        except Exception as e:
            st.error(f'Erro ao registrar conta, e-mail já existente no sistema!: {e}')
    else:
        st.error("Verifique os campos!")

def register_app():  

    nome_completo = st.text_input('Digite seu nome completo')
    nome_usuario = st.text_input('Digite seu nome de usuário (É um identificador de ID apenas)', value='Default')
    email = st.text_input('Digite seu e-mail', key='register_email')
    senha = st.text_input('Digite sua senha', type='password', key='register_password')
    senha2 = st.text_input('Digite sua senha novamente', type='password')

    st.success('Alguns exemplos de nomes de usuário: roberto_silva, roberto-oliveira, arthur356')
    st.warning('Alguns exemplos de nomes que não se deve colocar: jose padua, leonardo@prince, e aspas no nome de usuário')
    st.warning('Ou pode deixar o valor Default, que significa que gerará um ID automaticamente')
                            
    if st.button('Registrar a conta'):
        registrar_conta(nome_completo, nome_usuario, email, senha, senha2)
                
def forger_password_app():

    st.title('Sistema em construção')

with login:
    login_app()
        
with register:
    register_app()
with forget_password:
    forger_password_app()

if name == ‘main’:
main()

Your sample code is not correctly formatted. Could you format it properly?

Your post is very important to me because this concerns app security.

You wrote:

I encounter an issue. When I access the app from my PC, everything works as expected. But when I try to access it from my mobile device using the same link, it allows access to the content that should be restricted to logged-in users.

I deployed an app using streamlit-authenticator at digitalocean droplet and would like to test/experiment/explore its overall security vulnerability when there are more than 1 users accessing the app.

Tested:

  1. Access the app (with the given url) in my desktop, login with username and password and I have successfully access the app.
  2. On the phone visit the site with the same url, and I cannot fully access the app without entering the username and password. So no issues there.

Could you tell in detail regarding your issue?

Sorry, I will provide more details; perhaps the issue lies in this part:

import streamlit as st
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
from firebase_admin import auth
import re
import pyrebase
import streamlit as st
import streamlit_authenticator as stauth
import streamlit as st
from st_pages import Page, show_pages
import webbrowser

pages = [
Page(‘planilhas/full-acess/pages/shopee.py’, ‘Página Central’),
Page(‘planilhas/full-acess/main_full_acess.py’, ‘Configuração’)
]

firebaseConfig = {

}

if not firebase_admin._apps:
cred = credentials.Certificate(‘sistema-de-gerenciamento-5bbc6-d5e47ad2003f.json’)
default_app = firebase_admin.initialize_app(cred)

db = firestore.client()

firebase = pyrebase.initialize_app(firebaseConfig)
auth_pyrebase = firebase.auth()
db_pyrebase = firebase.database()
storage = firebase.storage()

def is_valid_gmail(email):
return re.match(r"[^@]+@gmail.com$", email)

def is_valid_username(username):

return re.match(r"^[a-zA-Z0-9_-]+$", username)

def obter_informacoes_do_usuario(email):
usuario_limit = db.collection(“usuários”).stream()
for usuario in usuario_limit:
acesso_dict = usuario.to_dict()
if acesso_dict.get(‘email’) == email:
return acesso_dict
return None

def update_value():
st.session_state.value = “Logar”

def main():

login, register, forget_password = st.tabs(['Logar', 'Registrar Conta', 'Esqueci a senha'])
    
query_params = st.experimental_get_query_params()

if "login" not in st.session_state:
       
    st.session_state["login"] = query_params.get("login", ["False"])[0]

usuario_fez_login = False

st.experimental_set_query_params(login="False")

def login_app(): 
    
    email = st.text_input('Digite seu e-mail', key='login_email')
    senha = st.text_input('Digite sua senha', type='password', key='login_password')


    if st.button('Logar', on_click=update_value):

    
        if is_valid_gmail(email):
            

            try:
                user = auth_pyrebase.sign_in_with_email_and_password(email, senha)
                st.success('Logado com sucesso!')

                usuario_fez_login = True
                    
                acesso_dict = obter_informacoes_do_usuario(email)
                
                if usuario_fez_login:
                    if acesso_dict:
                        if acesso_dict.get('Tipo de acesso') == 'user':
                            st.markdown('VOCÊ NÃO TEM ACESSO')
                        elif acesso_dict.get('Tipo de acesso') == 'full_acess':
                                

                            st.session_state["login"] = "True"

                            st.experimental_set_query_params(login="True")

                            show_pages(pages)

                            url = "http://localhost:8501/?selected=full-acess"

                            webbrowser.open(url, new=0)

    
                        elif acesso_dict.get('Tipo de acesso') == 'mid_acess':
                            st.markdown('VOCÊ TEM ACESSO, PORÉM LIMITADO!')
                    else:
                        st.markdown('ERROR!')
                else:
                    st.write("Erro Estranho! Contate com o desenvolvedor")

            except Exception as e:
                usuario_fez_login = False
                st.experimental_set_query_params(login="False")
                st.error('Erro ao logar, verifique se cadastrou essa conta ou se não digitou seu e-mail e senha errados') 
        
        else:
            st.error("Tipo de e-mail inválido, use gmail por gentileza!")

def registrar_conta(nome_completo, nome_usuario, email, senha, senha2):

    if senha != senha2:
        st.error('As senhas não coincidem')

    if nome_completo is None or nome_completo.strip() == "":
        st.error('O campo do nome completo não pode ficar em branco')

    if not is_valid_username(nome_usuario):
        st.error('Nome de usuário inválido')
                    
    if not is_valid_gmail(email):
        st.warning('Digite um e-mail gmail por gentileza, exemplo: example@gmail.com')
                    
    if senha == senha2 and nome_completo.strip() != "" and is_valid_username(nome_usuario) and is_valid_gmail(email):
        try:
            user = auth_pyrebase.create_user_with_email_and_password(email, senha)
            user_uid = user['localId']
            user_obj = auth.get_user(user_uid)
            updated_user = auth.update_user(user_uid, display_name=nome_usuario)

            hashed_password = stauth.Hasher(senha).generate()

            user_data = {
                'nome completo': nome_completo,
                'email': email,
                'nome do usuário': nome_usuario,
                'senha': hashed_password,
                'Tipo de acesso': 'user'  
            }
                                
            users_collection = db.collection('usuários')
            users_collection.document(user_uid).set(user_data)

            st.success('Usuário registrado com sucesso')
            st.markdown('Agora use seu e-mail e senha para logar!')

        except Exception as e:
            st.error(f'Erro ao registrar conta, e-mail já existente no sistema!: {e}')
    else:
        st.error("Verifique os campos!")

def register_app():  

    nome_completo = st.text_input('Digite seu nome completo')
    nome_usuario = st.text_input('Digite seu nome de usuário (É um identificador de ID apenas)', value='Default')
    email = st.text_input('Digite seu e-mail', key='register_email')
    senha = st.text_input('Digite sua senha', type='password', key='register_password')
    senha2 = st.text_input('Digite sua senha novamente', type='password')

    st.success('Alguns exemplos de nomes de usuário: roberto_silva, roberto-oliveira, arthur356')
    st.warning('Alguns exemplos de nomes que não se deve colocar: jose padua, leonardo@prince, e aspas no nome de usuário')
    st.warning('Ou pode deixar o valor Default, que significa que gerará um ID automaticamente')
                            
    if st.button('Registrar a conta'):
        registrar_conta(nome_completo, nome_usuario, email, senha, senha2)
                
def forger_password_app():

    st.title('Sistema em construção')

with login:
    login_app()
        
with register:
    register_app()
with forget_password:
    forger_password_app()

if name == ‘main’:
main()

When a user logs in and then accesses the site from another device, it seems that the application now understands that this is the main application. This is the part where I need help because the web app is divided into different access types. Users need to log in to enter the site, and depending on their access, they should enter a different section of the web app.

“pages = [
Page(‘planilhas/full-acess/pages/shopee.py’, ‘Página Central’),
Page(‘planilhas/full-acess/main_full_acess.py’, ‘Configuração’)
]”