Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

making cookie based login work. #25

Open
0-MegaMind-0 opened this issue Mar 6, 2022 · 2 comments
Open

making cookie based login work. #25

0-MegaMind-0 opened this issue Mar 6, 2022 · 2 comments

Comments

@0-MegaMind-0
Copy link

0-MegaMind-0 commented Mar 6, 2022

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

@0-MegaMind-0
Copy link
Author

0-MegaMind-0 commented Mar 6, 2022

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.

@AravindRK99
Copy link

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 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants