In the previous tutorial we learnt how to build a simple CRuD app with Streamlit for blogging. Our blog had no login page hence in this post, we will see how to add a login and signup section to our initial app. We will start with a simple app demonstrating the concept and then apply the concept on our initial CRUD app.
Note: This is a simple workaround, hopefully in the future with more features being added we will revisit this post.
What we will be doing is that, we will move some of the sections of the app such as the
Add Posts,Manage Blog section to a restricted section – which will be only accessible to people who have signed up and have logged in.
Just as we initially used SQLite3 we will add another table for users to sign up.
You can use any Database software but let us go with the simplest for now.
Creating the SignUp Section/Page
In this section we will give the option to signup or create a new account. The details received will be stored into our database. This is what will be used to check if the user has access to the restricted sections of the app. We will then create individual functions to create the user’s table and another to add the details to our database.
We will add these functions for managing this aspect.
# DB Management
import sqlite3
conn = sqlite3.connect('data.db')
c = conn.cursor()
def create_usertable():
c.execute('CREATE TABLE IF NOT EXISTS userstable(username TEXT,password TEXT)')
def add_userdata(username,password):
c.execute('INSERT INTO userstable(username,password) VALUES (?,?)',(username,password))
conn.commit()
def login_user(username,password):
c.execute('SELECT * FROM userstable WHERE username =? AND password = ?',(username,password))
data = c.fetchall()
return data
We will add the signup section with areas for receiving text input from the user as below.
elif choice == "SignUp":
st.subheader("Create an Account")
new_user = st.text_input('Username')
new_passwd = st.text_input('Password',type='password')
if st.button('SignUp'):
create_usertable()
add_userdata(new_user,make_hashes(new_passwd))
st.success("You have successfully created an account.Go to the Login Menu to login")
When a user clicks on the SignUp button, the data will be sent to our database. It is recommended to encrypt or hash the details to make it more secure,since storing user input and passwords in plaintext is not recommended and can result in bad outcomes from hackers. Notice that hashing and encryption are different methods of keeping our plaintext secure.
We can use any of the various hashing libraries or password encrypting libraries such as
- passlib
- hashlib
- bcrypt
- scrypt
We will encrypt the user password after the user has entered in the details and then store the hashed/encrypted password to the database not the plaintext password. We will create various functions to help us with that using some hashing libraries.
import hashlib
def make_hashes(password):
return hashlib.sha256(str.encode(password)).hexdigest()
def check_hashes(password,hashed_text):
if make_hashes(password) == hashed_text:
return hashed_text
return False
# You can also use the verify functions of the various libraries for the same purpose
Below is a picture that explains what we will be doing
This makes it more secure.
Creating the Login Page
Having created the signup page/section we will create another section to allow the user to login/sign-in in order to have access to the restricted section of the app.
When the user enters the credentials we will hash the password and then check the database if it exist and if true we will grant him access.
We can use normal SQL code to do the login in and hashlib for the hashing of the plaintext password. In the future we will discuss more into details about data protection,encryption and hashing.
elif choice == "Login":
user = st.sidebar.text_input('Username')
passwd = st.sidebar.text_input('Password',type='password')
if st.sidebar.checkbox('Login') :
create_usertable()
hashed_pswd = make_hashes(passwd)
result = login_user(user,check_hashes(passwd,hashed_pswd))
if result:
st.success("Logged In as {}".format(user))
# Tasks For Only Logged In Users
task = st.selectbox('Select Task',['Add Posts','Manage Blog','Profile'])
if task == "Add Posts":
st.subheader("Add Articles")
....
We have seen how to add a login section and a signup section to our streamlit app.
Having understood the concept we can then apply all these to our main blog app we built. Remember that this is a workaround but hopefully we will improve on it as time goes on. You can get the entire code here or below
import streamlit as st
import pandas as pd
# Security
#passlib,hashlib,bcrypt,scrypt
import hashlib
def make_hashes(password):
return hashlib.sha256(str.encode(password)).hexdigest()
def check_hashes(password,hashed_text):
if make_hashes(password) == hashed_text:
return hashed_text
return False
# DB Management
import sqlite3
conn = sqlite3.connect('data.db')
c = conn.cursor()
# DB Functions
def create_usertable():
c.execute('CREATE TABLE IF NOT EXISTS userstable(username TEXT,password TEXT)')
def add_userdata(username,password):
c.execute('INSERT INTO userstable(username,password) VALUES (?,?)',(username,password))
conn.commit()
def login_user(username,password):
c.execute('SELECT * FROM userstable WHERE username =? AND password = ?',(username,password))
data = c.fetchall()
return data
def view_all_users():
c.execute('SELECT * FROM userstable')
data = c.fetchall()
return data
def main():
"""Simple Login App"""
st.title("Simple Login App")
menu = ["Home","Login","SignUp"]
choice = st.sidebar.selectbox("Menu",menu)
if choice == "Home":
st.subheader("Home")
elif choice == "Login":
st.subheader("Login Section")
username = st.sidebar.text_input("User Name")
password = st.sidebar.text_input("Password",type='password')
if st.sidebar.checkbox("Login"):
# if password == '12345':
create_usertable()
hashed_pswd = make_hashes(password)
result = login_user(username,check_hashes(password,hashed_pswd))
if result:
st.success("Logged In as {}".format(username))
task = st.selectbox("Task",["Add Post","Analytics","Profiles"])
if task == "Add Post":
st.subheader("Add Your Post")
elif task == "Analytics":
st.subheader("Analytics")
elif task == "Profiles":
st.subheader("User Profiles")
user_result = view_all_users()
clean_db = pd.DataFrame(user_result,columns=["Username","Password"])
st.dataframe(clean_db)
else:
st.warning("Incorrect Username/Password")
elif choice == "SignUp":
st.subheader("Create New Account")
new_user = st.text_input("Username")
new_password = st.text_input("Password",type='password')
if st.button("Signup"):
create_usertable()
add_userdata(new_user,make_hashes(new_password))
st.success("You have successfully created a valid Account")
st.info("Go to Login Menu to login")
if __name__ == '__main__':
main()
You can check the video tutorial below.
Thank You For Your Time
Jesus Saves
By Jesse E.Agbe(JCharis)
It works, but if I run a widget (ie. streamlit.file_uploader() ) it logs out. Any advice? Thank you
Hi Martina, you can use the st.checkbox() function to keep it log in for now.
In the future we will be able to use session state to help us achieve a better result.
Hope this helps