I am attempting to integrate the flask-authentication into my app, as @AnnMarieW demonstrated here
I am trying to move all authentication lines of code into their own module including the callback.
However, when I run this, I get the following error:
An object was provided as `children` instead of a component, string, or number (or list of those). Check the children property that looks something like:
{
"0": {
"props": {
"pathname": "/",
"href": "http://127.0.0.1:8050/"
}
}
}
I have been at this for several hours now and still cannot figure out how to make this work, or if it is even possible.
Any help is appreciated. thank you!
****************app.py :
from flask import Flask
import dash
import src.page_container as page_container
import src.pages.login_callback as login_callback
server = Flask(__name__)
app = dash.Dash(
__name__,
server=server,
use_pages=True,
suppress_callback_exceptions=True,
pages_folder='src'
)
login_callback.function1(app, server)
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, current_user
import dash
from dash import dcc, Input, Output, State
VALID_USERNAME_PASSWORD = {"test": "test", "hello": "world"}
def function1(app, server):
# Updating the Flask Server configuration with Secret Key to encrypt the user session cookie
server.config.update(SECRET_KEY='abcd1234')
# Login manager object will be used to login / logout users
login_manager = LoginManager()
login_manager.init_app(server)
login_manager.login_view = "/login"
class User(UserMixin):
# User data model. It has to have at least self.id as a minimum
def __init__(self, username):
self.id = username
@login_manager.user_loader
def load_user(username):
return User(username)
@app.callback(
Output("user-status-header", "children"),
Input("url", "pathname"),
)
def update_authentication_status(_):
if current_user.is_authenticated:
return dcc.Link("logout", href="/logout")
return dcc.Link("login", href="/login")
@app.callback(
Output("output-state", "children"),
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 > 0:
if VALID_USERNAME_PASSWORD.get(username) is None:
return "Invalid username"
if VALID_USERNAME_PASSWORD.get(username) == password:
login_user(User(username))
return "Login Successful"
return "Incorrect password"
****************home.py :
import dash
from dash import html, dcc
from flask_login import current_user
dash.register_page(__name__, path="/")
def layout():
if not current_user.is_authenticated:
return html.Div(["Please ", dcc.Link("login", href="/login"), " to continue"])
return html.Div([dcc.Link("Go to Page 1", href="/page-1")])
****************login.py :
import dash
from dash import html, dcc
import dash_bootstrap_components as dbc
import dash_mantine_components as dmc
dash.register_page(__name__, path="/login")
text_input_style = {
'padding': '5px',
'margin':'auto',
'margin-top':'5px',
'margin-bottom':'5px',
#'border-color': '#878787',
#'border-radius': 5,
'width':'400px'
}
layout = dbc.Container([
dbc.Row([
dbc.Col([
dmc.Group(direction='column', spacing='xs', position='center', children=[
dbc.Input(
id='username',
placeholder='username',
style=text_input_style
),
dbc.Input(
id='password',
placeholder='password',
style=text_input_style
),
html.Button(children="Login", n_clicks=0, type="submit", id="login-button"),
html.Div(children="", id="output-state"),
html.Br(),
dcc.Link("Home", href="/")
])
])
])
], fluid=True
)
****************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("You have been logged out - Please login")),
html.Br(),
dcc.Link("Home", href="/"),
]
)
****************page_container.py :
import dash
from dash import dcc, html
def main_layout(app):
app.layout = html.Div(
[
dcc.Location(id="url"),
html.Div(id="user-status-header"),
html.Hr(),
dash.page_container,
]
)