Hi @adamschroeder ,
Since I’m interested as well in the topic, I have combined the tutorials mentioned above with the new Dash pages of Dash Labs tutorial.
The app consists out of app.py file, where the flask auth is setup. Next, 3 pages: login.py (login page layout & does auth), home.py and historical_analysis.py (example pages of Dash Labs tutorial). This is what the folder looks like:
app.py
.env
/pages
--- home.py
--- login.py
--- historical_analysis.py
I’m running into similar issue as reported by @MarcooPoloo. Whenever you add the Flask auth code, the dash.register_page seems to only find the ‘login.py’ file. The ‘flask_login’ & class ‘User’ imports in login.py seem to interfer with the registering of the pages. The navbar will only show the ‘login’ page and not all three pages (login, home & historical_analysis).
Below you can find the code.
app.py
import dash
import dash_labs as dl
import dash_bootstrap_components as dbc
from dash import dcc, html
from dash.dependencies import Input, Output, State
import flask
import os
from flask_login import login_user, LoginManager, UserMixin, logout_user, current_user
# Exposing the Flask Server to enable configuring it for logging in
server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server,
title='Example Dash login',
update_title='Loading...',
suppress_callback_exceptions=True, plugins=[dl.plugins.pages], external_stylesheets=[dbc.themes.BOOTSTRAP])
# Updating the Flask Server configuration with Secret Key to encrypt the user session cookie
server.config.update(SECRET_KEY=os.getenv('SECRET_KEY'))
# Login manager object will be used to login / logout users
login_manager = LoginManager()
login_manager.init_app(server)
login_manager.login_view = '/login'
# User data model. It has to have at least self.id as a minimum
class User(UserMixin):
def __init__(self, username):
self.id = username
@ login_manager.user_loader
def load_user(username):
''' This function loads the user by user id. Typically this looks up the user from a user database.
We won't be registering or looking up users in this example, since we'll just login using LDAP server.
So we'll simply return a User object with the passed in username.
'''
return User(username)
navbar = dbc.NavbarSimple([
dbc.NavItem(dbc.NavLink(page['name'], href=page['path']))
for page in dash.page_registry.values()
if page["module"] != "pages.not_found_404"
], brand='Dash App')
app.layout = dbc.Container(
[navbar, dl.plugins.page_container, html.Div(id="logincheck_div"), html.Div(id="output_div")],
)
@app.callback(
Output("output_div","children"),
Input("logincheck_div","children"),
)
def check_logged_in(div):
if current_user.is_authenticated:
print("User is logged in")
else:
print("User is not logged in, you are being redirected.")
return(dcc.Location(id="redirect",pathname="/login"))
if __name__ == "__main__":
app.run_server(debug=True)
.env
login.py
import dash
from dash import dcc, html, Input, Output, callback, State
import dash_bootstrap_components as dbc
from flask_login import login_user, LoginManager, UserMixin, logout_user, current_user
from app import User
dash.register_page(__name__, path="/login")
layout = html.Div([
html.H1('Login page'),
dbc.Label("Username"),
dbc.Input(id = "input_username"),
dbc.Label("Password"),
dbc.Input(id = "input_password"),
dbc.Button("Login in", id = "button_login"),
dbc.Label("Please login", id = "label_feedback"),
dcc.Location(id="redirect"),
])
@callback(
Output('redirect', 'pathname'),
Output('label_feedback', 'children'),
Input('button_login', 'n_clicks'),
State('input_username', 'value'),
State('input_password', 'value')
)
def login_button_click(n_clicks, username, password):
if n_clicks != 0:
if username == 'test2' and password == 'test':
user = User(username)
login_user(user)
return (("/"),'Succesfully logged in!')
else:
return (None, 'Incorrect username or password')
Excuse any rookie mistakes. I’m quite new to Dash, and even less to Flask (but here to learn! )