I apologize for the length of code - I pushed it to a GitHub repo to make it easier to work with.
The problems I have been running into (and have spent the last several days trying to solve):
- When I log into the app, it only ‘recognizes’ the login after I manually refresh the page. Otherwise, I can enter the correct credentials repeatedly and it will just say on the login page
- Page 1 has a nav menu along the left side. I would like to be able to show a different menu based on the username that was used during login. However, I don’t know how to get this variable outside of the callback function. FWIW, the app I am trying to build is ~10 pages, and all of them have this nav menu.
Any help with these would be EXTREMELY appreciated!
app.py:
import dash
import dash_bootstrap_components as dbc
import src.page_container as page_container
from src.pages.login_callback import server
app = dash.Dash(
__name__,
server=server,
use_pages=True,
pages_folder='src',
external_stylesheets=[dbc.themes.BOOTSTRAP]
)
page_container.main_layout(app)
if __name__ == "__main__":
app.run_server(debug=True)
login_callback.py:
from flask import Flask
from flask_login import login_user, LoginManager, UserMixin
import dash
from dash import Input, Output, State
from dash.exceptions import PreventUpdate
VALID_USERNAME_PASSWORD = {"user1": "pw", "user2": "pw"}
FLASK_SECRET_KEY='abcd1234'
server = Flask(__name__)
class User(UserMixin):
def __init__(self, username):
self.id = username
server.config.update(SECRET_KEY=FLASK_SECRET_KEY)
login_manager = LoginManager()
login_manager.init_app(server)
login_manager.login_view = "/login"
@login_manager.user_loader
def load_user(username):
return User(username)
@dash.callback(
Output("redirect", "href"),
Output("output-state", "children"),
Output("session_user", "data"),
Input("login-button", "n_clicks"),
State("username", "value"),
State("password", "value"),
prevent_initial_call=True,
)
def login_button_click(n_clicks, username, password):
if n_clicks:
if VALID_USERNAME_PASSWORD.get(username) is None:
return '/login', 'please enter pw', None
elif VALID_USERNAME_PASSWORD.get(username) == password:
login_user(User(username))
return '/page-1', '', username
elif VALID_USERNAME_PASSWORD.get(username) != password:
return '/login', 'wrong pw', None
else: raise PreventUpdate
page_container.py:
import dash
from dash import dcc, html
import dash_bootstrap_components as dbc
from flask_login import current_user
def main_layout(app):
app.layout = dbc.Container([
dcc.Store(id="session_user", storage_type="session"),
html.Div([dash.page_container]),
], fluid=True)
page-1.py:
import dash
from dash import html, dcc
from flask_login import current_user
import dash_bootstrap_components as dbc
dash.register_page(__name__, path="/page-1")
if username == user1:
navigation = dbc.Nav([
dbc.NavLink('user1 page-1', href='/page-1'),
dbc.NavLink('user1 page-2', href='page-2'),
dbc.NavLink('user1 logout', href='/logout')
], vertical=True, pills=True)
elif username == user2:
navigation = dbc.Nav([
dbc.NavLink('user2 page-1', href='/page-1'),
dbc.NavLink('user2 page-2', href='page-2'),
dbc.NavLink('user2 logout', href='/logout')
], vertical=True, pills=True)
def layout():
if not current_user.is_authenticated:
return html.Div([dcc.Link("login", href="/login"), " to continue"])
return dbc.Container([
dbc.Row([
dbc.Col([
navigation
]),
dbc.Col([
html.H1("Page 1"),
dcc.Link("Go to page 2", href="/page-2")
]),
]),
])
page-2.py:
import dash
from dash import html, dcc
from flask_login import current_user
dash.register_page(__name__, path="/page-2")
def layout():
if not current_user.is_authenticated:
return html.Div([dcc.Link("login", href="/login"), " to continue"])
return html.Div([
html.H1("Page 2"),
dcc.Link("Go to page 1", href="/page-1")
])
login.py:
import dash
from dash import html, dcc
dash.register_page(__name__, path="/login")
layout = html.Div([
dcc.Input(id='username', placeholder='username'),
dcc.Input(id='password', placeholder='password'),
dcc.Link(
html.Button("Login", id="login-button"),
id='redirect',
href='/page-1'
),
html.Div(children="", id="output-state"),
])
logout.py:
import dash
from dash import html, dcc
from flask_login import logout_user, current_user
dash.register_page(__name__, path="/logout")
def layout():
if current_user.is_authenticated:
logout_user()
return html.Div([
html.Div(html.H2("Please login")),
dcc.Link("Login", href="/login"),
])