Daniel
Daniel

Reputation: 101

If user queries server or jumps to another dashboard, the session information gets lost

I am having issues trying to find a solution for keeping the authentication of a user using plotly dash with flask and gunicorn. It seems that if another user queries the server or even after a while of jumping from one dashboard to the other, the session user information gets lost.

# app.py

import dash
import dash_bootstrap_components as dbc
from dash import html, dcc, Input, Output, State
from flask import Flask, session
from flask_session import Session
from redis import Redis
from datetime import timedelta
import os
import secrets

# Initialize the Flask server
server = Flask(__name__)
server.secret_key = os.environ.get('SECRET_KEY', secrets.token_urlsafe(16))

# Configure Flask-Session with Redis
server.config["SESSION_TYPE"] = "redis"
server.config["SESSION_PERMANENT"] = True
server.config["SESSION_USE_SIGNER"] = True
server.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=30)
server.config["SESSION_REDIS"] = Redis(host='localhost', port=6379)  # Adjust Redis host/port if needed

# Initialize Flask-Session
Session(server)

# Initialize the Dash app
app = dash.Dash(__name__, server=server, external_stylesheets=[dbc.themes.BOOTSTRAP], suppress_callback_exceptions=True)

# Layout for login modal and navbar
app.layout = html.Div([
    dcc.Location(id='url', refresh=True),
    html.Div(id='page-content'),
    dbc.Modal(
        [
            dbc.ModalHeader("Login"),
            dbc.ModalBody([
                dbc.Input(id='username', type='text', placeholder='Username'),
                dbc.Input(id='password', type='password', placeholder='Password'),
                dbc.Button('Login', id='login-button', color="primary")
            ]),
        ], id="login-modal", is_open=True
    ),
    dbc.NavbarSimple(
        children=[
            dbc.Button("Logout", id="logout-button", color="danger", className="ml-auto")
        ], brand="App", color="dark", dark=True, id='navbar', style={'display': 'none'}
    ),
])

# Simulated user database
USER_DATABASE = {
    'test_user': 'test_password',
    'test_user2': 'test_password',
}

@app.server.before_request
def refresh_session():
    session.modified = True  # Refresh session TTL on each request

# Callback to handle login and logout
@app.callback(
    [Output('login-modal', 'is_open'), Output('navbar', 'style')],
    [Input('login-button', 'n_clicks'), Input('logout-button', 'n_clicks')],
    [State('username', 'value'), State('password', 'value')],
    prevent_initial_call=True
)
def handle_login_logout(n_login, n_logout, username, password):
    # Login process
    if n_login and username in USER_DATABASE and USER_DATABASE[username] == password:
        session['user'] = {'username': username}  # Store user session
        return False, {'display': 'block'}  # Close login modal, show navbar

    # Logout process
    if n_logout:
        session.pop('user', None)  # Clear session
        return True, {'display': 'none'}  # Reopen login modal, hide navbar

    return dash.no_update, dash.no_update

# Redirect logic
@app.callback(
    Output('page-content', 'children'),
    [Input('url', 'pathname')]
)
def display_page(pathname):
    if 'user' in session:
        return html.Div([html.H1(f"Welcome, {session['user']['username']}"), html.P("This is your dashboard.")])
    return html.Div([html.H1("Please log in to access this page.")])

if __name__ == '__main__':
    app.run_server(debug=True)

The following is a dashboard under ‘pages’ directory:

$ home.py

import dash
import dash_bootstrap_components as dbc
from dash import html, dcc
from flask import session
import dash

dash.register_page(__name__)

def layout():
    # Check if user data is available in the session
    user = session.get('user')

    if not user:
        # Redirect to a login page or show a message if no user is found in session
        return html.Div("Please log in to access this page.")

    # Display the user's info pulled from the session
    return dbc.Container(fluid=True, children=[
        dbc.Row([
            dbc.Col([
                html.H2(f"Welcome, {user['username']}!"),
                html.P("This is your personal dashboard."),
                html.P(f"Email: {user['email']}"),
                dbc.Button("Logout", id="logout-button", color="danger", className="mt-3")
            ], width=6)
        ], justify="center")
    ])

Can someone please tell me how I can retain an individual users session information in order for me to ensure the user is authenticated and that I can pull user tailored data from a database, if I wanted to? The issue that I keep seeing is that the session stored data keeps being deleted if another user is querying anything from the server.

Upvotes: 0

Views: 30

Answers (0)

Related Questions