making cookie based login work.
0-MegaMind-0 opened this issue ยท 2 comments
So I was trying to hold a JWT token in cookie when login button is pressed.
app.py
import hydralit as hy
import streamlit as st
from hydralit_components import CookieManager
from login import LoginApp
cookie_manager = CookieManager()
app = hy.HydraApp(title='test', favicon="๐", hide_streamlit_markers=True,
allow_url_nav=True, sidebar_state="expanded",
layout='wide'
)
app.add_app("Login", LoginApp(cookie_manager=cookie_manager), is_login=True, logout_label="Logout")
@app.logout_callback
def mylogout_cb():
cookie_manager.delete('user_data')
print('I was called from Hydralit at logout!')
@app.login_callback
def mylogin_cb():
print('I was called from Hydralit at login!')
login.py
class LoginApp(HydraHeadApp):
"""
This is an example login application to be used to secure access within a HydraApp streamlit application.
This application implementation uses the allow_access session variable and uses the do_redirect method if the login check is successful.
"""
def __init__(self, cookie_manager, title='', **kwargs):
self.__dict__.update(kwargs)
self.title = title
self.cookie_manager = cookie_manager
def _check_cookie_login(self) -> dict | None:
"""
Check if the user is logged in.
"""
session_cookie = self.cookie_manager.get("user_data")
if session_cookie:
return {'user': 'joe', 'level': 1}
# ToDo: Check parse jwt and check if its valid and then return the user dict
def run(self) -> None:
"""
Application entry point.
"""
login = self._check_cookie_login()
if login:
self.set_access(1, login['user'], cache_access=True)
self.do_redirect()
st.markdown("<h1 style='text-align: center;'>Secure Hydralit Login</h1>", unsafe_allow_html=True)
c1, c2, c3, = st.columns([2, 2, 2])
form_data = self._create_login_form(c2)
pretty_btn = """
<style>
div[class="row-widget stButton"] > button {
width: 100%;
}
</style>
<br><br>
"""
c2.markdown(pretty_btn, unsafe_allow_html=True)
if form_data['submitted']:
self._do_login(form_data, c2)
@staticmethod
def _create_login_form(parent_container) -> Dict:
login_form = parent_container.form(key="login_form")
form_state = {}
form_state['username'] = login_form.text_input('Username')
form_state['password'] = login_form.text_input('Password', type="password")
form_state['submitted'] = login_form.form_submit_button('Login')
parent_container.write("sample login -> joe & joe")
return form_state
def _do_login(self, form_data, msg_container) -> None:
# access_level=0 Access denied!
access_level = self._check_login(form_data)
if access_level > 0:
msg_container.success(f"โ๏ธ Login success")
with st.spinner("๐ค now redirecting to application...."):
time.sleep(1)
self.set_access(1, form_data['username'], cache_access=True)
self.cookie_manager.set("user_data", 'True')
# Do the kick to the home page
self.do_redirect()
else:
self.session_state.allow_access = 0
self.session_state.current_user = None
msg_container.error(f"โ Login unsuccessful, ๐ please check your username and password and try again.")
def _check_login(self, login_data) -> int:
if login_data['username'] == 'joe' and login_data['password'] == 'joe':
return 1
else:
return 0
The above basically checks if there is a cookie with name user_data
and logs in automatically if its set.
When the cookie is not found it loads the modified example from example code.
When the username and password matches. It should set a cookie with name user_data
but this fails here.
But doing the same using login_callback in app.py works
@app.logout_callback
def mylogout_cb():
cookie_manager.delete('user_data')
print('I was called from Hydralit at logout!')
@app.login_callback
def mylogin_cb():
print('I was called from Hydralit at login!')
cookie_manager.set('user_data', "Joe")
Now whenever I reload the page I can skip the login page. But hitting the logout button sends invokes the mylogout_cb
function. But cookie_manager.delete('user_data')
has no effect and doesn't delete the cookie.
But putting the same cookie_manager.delete('user_data')
inside the mylogin_cb
callback actually deletes the cookie on next login / on page reload.
Am i missing something here ?. What would be the best way for me to achieve this. I tried extra_streamlit_components library and it has the same behaviour
Just gave https://github.com/ktosiek/streamlit-cookies-manager a try. everything works as expected. Cookies get saved when login button is pressed (code for saving the jwt cookie is in the LoginApp).
Cookies get deleted when logout_callback is invoked.
How are you able to achieve a logout button in your code? I am able to login but I get an error saying that an app named Logout doesn't exist. What could I do to rectify this error ?