Streamlit login and mutipages

import streamlit as st
from pages import home_page, profile_page

Page for login

if not hasattr(st.session_state, ‘username’) or st.session_state.username is None:
st.header(“Login”)

# Create an empty container
placeholder = st.empty()

actual_email = "email"
actual_password = "password"

# Insert a form in the container
with placeholder.form("login"):
    st.markdown("#### Enter your credentials")
    email = st.text_input("Email")
    password = st.text_input("Password", type="password")
    submit = st.form_submit_button("Login")

if submit:
    if email == actual_email and password == actual_password:
        placeholder.empty()
        st.success("Login successful")
        st.session_state.username = email
        st.session_state.page = "home_page"
    else:
        st.error("Invalid credentials. Please try again.")

else:
# Navigation sidebar
st.sidebar.header(“Navigation”)
pages = [“Home”, “Profile”]
selected_page = st.sidebar.radio(“Select Page”, pages)

# Display the selected page content
if selected_page == "Home":
    home_page.show()
elif selected_page == "Profile":
    profile_page.show()

Hi, Recently i started learning streamlit, i have simple login screen. I have few queries how do i achieve it. Like my initial logion should only be login page. after successful login user should have access of the rest of the pages.

Here is an example. Create a session variable in main.py and page1.py.

As session variable is like a global variable. But it gets wiped out when you refresh the page. Hence it only exists per session basis.

Search and study session state. This is very important in manipulating variables around streamlit app.

Folder structure

main.py
pages/
    page1

Codes

main.py

if 'oklogin' not in st.session_state:
    # This is our variable.
    st.session_state.oklogin = False

if email == actual_email and password == actual_password:
    st.session_state.oklogin = True

if st.session_state.oklogin:
    # Your content here

page1.py

if 'oklogin' not in st.session_state:
    st.session_state.oklogin = False

if st.session_state.oklogin:
    # Your content here
else:
    st.error('Please log in in the main page.')

@ferdy , thanks for your response

main.py

import streamlit as st
from pages import page1

# Page for login
if not hasattr(st.session_state, 'username') or st.session_state.username is None:
    st.header('Login')

# Create an empty container
placeholder = st.empty()

actual_email = "email"
actual_password = "password"

# Insert a form in the container
with placeholder.form("login"):
    st.markdown("#### Enter your credentials")
    email = st.text_input("Email")
    password = st.text_input("Password", type="password")
    submit = st.form_submit_button("Login")

if 'oklogin' not in st.session_state:
    # This is our variable.
    st.session_state.oklogin = False

if email == actual_email and password == actual_password:
    st.session_state.oklogin = True

if st.session_state.oklogin:
    # Your content here
    if email == actual_email and password == actual_password:
        placeholder.empty()
        st.success("Login successful")
        st.session_state.username = email
        st.session_state.page = page1
    else:
        st.error("Invalid credentials. Please try again.")

page1.py


import streamlit as st

if 'oklogin' not in st.session_state:
    st.session_state.oklogin = False

if st.session_state.oklogin:
    st.info('Home Page')
    st.balloons()
else:
    st.error('Please log in in the main page.')

still in initial login page 1 is visible, with info “Please log in in the main page”, it should be hidden or not available until the sucessfull login. and post sucessfull login main.py (login.py) should not be visible, only the list of pages should be available.

Under normal streamlit usage this is not possible. But instead of totally hiding the page why not just make it empty or not showing its contents.

So we can have for example a home page, login page and profile page. At the start the main page will be rendered since we have not logged in yet we will not show its content. Then we switch to login page to login. Once logged in, we will not show its contents and switch to main page and this time show its content. In summary if we are not logged in yet, all pages’s content will not be displayed except the login page. Once logged in, all pages’s content will be visible except the login page. The logout button will be shown in the main page.

Minimal example code

main.py

import streamlit as st


USERS = {
    "info": [
        {
            "username": "johnwall",
            "email": "john@gmail.com",
            "password": "Kqhml5dw"
        },
        {
            "username": "peterwall",
            "email": "peter@gmail.com",
            "password": "t4Pu78bV"
        }
    ]
}


if 'profile' not in st.session_state:
    st.session_state.profile = {}
    
if 'oklogin' not in st.session_state:
    st.session_state.oklogin = False
    st.switch_page('pages/login.py')


def logout_cb():
    st.session_state.oklogin = False


# Show content if logged in.
if st.session_state.oklogin:
    st.subheader('Main page')

    with st.sidebar:
        st.button('Logout', on_click=logout_cb)

    st.write('List of Users')
    st.dataframe(USERS['info'])

pages/login.py

import time
import streamlit as st
from main import USERS


if 'oklogin' not in st.session_state:
    st.session_state.oklogin = False
if 'profile' not in st.session_state:
    st.session_state.profile = {}


def login_cb():
    """Updates oklogin state if form submit is clicked."""
    for ui in USERS['info']:
        if (ui['email'] == st.session_state.email
                and ui['password'] == st.session_state.password):
            st.session_state.oklogin = True
            st.session_state.profile = ui
            break
    if not st.session_state.oklogin:
        st.error('email and/or password are incorrect.')


# Show login form.
if not st.session_state.oklogin:
    with st.form('login form', clear_on_submit=True):
        st.text_input('Email', key='email')
        st.text_input('Password', key='password', type='password')
        st.form_submit_button('Login', on_click=login_cb)
else:
    time.sleep(0.1)  # make the page switch visible    
    st.switch_page('main.py')

pages/profile.py

import streamlit as st 


if 'profile' not in st.session_state:
    st.session_state.profile = {}

if 'oklogin' not in st.session_state:
    st.session_state.oklogin = False
    st.switch_page('pages/login.py')

# Show content if logged in.
if st.session_state.oklogin:
    st.subheader('Profile')

    st.write("User's profile")
    st.json(st.session_state.profile)

@ferdy,

I am getting the below error, when i try to execute the code.

pages

Could you show your requirements.txt?

python 3.10.5
streamlit 1.30.0
st-pages 0.4.5

This library could be the cause of that error.

@ferdy, I came across a similar approach.

main.py

import streamlit as st
from pathlib import Path
import json
from streamlit_extras.switch_page_button import switch_page
from streamlit.source_util import _on_pages_changed, get_pages

DEFAULT_PAGE = "main.py"
SECOND_PAGE_NAME = "dashboard"


def get_all_pages():
    """Get all pages"""
    default_pages = get_pages(DEFAULT_PAGE)

    pages_path = Path("pages.json")

    if pages_path.exists():
        saved_default_pages = json.loads(pages_path.read_text())
    else:
        saved_default_pages = default_pages.copy()
        pages_path.write_text(json.dumps(default_pages, indent=4))

    return saved_default_pages

def clear_all_ex_first_page():
    """Clear all the except Login"""
    current_pages = get_pages(DEFAULT_PAGE)

    if len(current_pages.keys()) == 1:
        return

    get_all_pages()

    key, val = list(current_pages.items())[0]
    current_pages.clear()
    current_pages[key] = val

    _on_pages_changed.send()


def show_all_pages():
    """Show all Pages"""
    current_pages = get_pages(DEFAULT_PAGE)

    saved_pages = get_all_pages()
    for key in saved_pages:
        if key not in current_pages:
            current_pages[key] = saved_pages[key]

    _on_pages_changed.send()

def hide_page(name: str):
    """Hide Default Page"""
    current_pages = get_pages(DEFAULT_PAGE)

    for key, val in current_pages.items():
        if val["page_name"] == name:
            del current_pages[key]
            _on_pages_changed.send()
            break

clear_all_ex_first_page()
def main():
    st.header("Login")
    username = st.text_input("Username")
    password = st.text_input("Password", type="password")

    submit = st.button("Login")

    if submit:
        if username == 'test' and password == 'test':
            st.success("Logged In Sucessful")
            show_all_pages()
            hide_page(DEFAULT_PAGE.replace(".py", ""))
            switch_page(SECOND_PAGE_NAME)
        else:
            st.error("Invalid Username or Password")
            clear_all_ex_first_page()

if __name__ == '__main__':
    main()

dashboard.py

import streamlit as st

st.header('Dashboard Page')

pages.json

{
    "f9c60c555085a6adc9666485bc4822d23":{
        "page_script_hash":"f9c60c555085a6adc9666485bc4822d23",
        "page_name":"main",
        "icon":"",
        "script_path":"main.py"
    },
    "f9c60c777085a6adc9888485bc4822d23":{
        "page_script_hash":"f9c60c777085a6adc9888485bc4822d23",
        "page_name":"dashboard",
        "icon":"",
        "script_path":"pages/dashboard.py"
    },
    "f9c60c998085a6adc9898485bc4822d23":{
        "page_script_hash":"f9c60c998085a6adc9898485bc4822d23",
        "page_name":"logout",
        "icon":"",
        "script_path":"pages/logout.py"
    }
}

logout.py

from main import clear_all_ex_first_page

clear_all_ex_first_page()

is this the correct way.
and also here logout page is not working.

Version:
python 3.10.5
streamlit 1.30.0
streamlit_extras 0.3.6

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.