So where’s the Dash 1.0 release thread? The part about making dash work like other flask extensions excites me more than anything. Anyway,…
Before Dash 1.0 release, I had a function like below that I would call after creating dash app and setting a flask app to it as the server.
def protect_views(app):
for view_func in app.server.view_functions:
if view_func.startswith(app.url_base_pathname):
app.server.view_functions[view_func] = login_required(app.server.view_functions[view_func])
return app
With the Dash 1.0 update, there’s a nice and consistent way to declare a dash app without a server and then using the the init_app(app) function to pass a standard flask application to it. My question is, if I’m also using flask-login, how do I protect the routes of the dash app after calling the init_app to give dash a server? My setup with the factory pattern with Blueprints is shown below.
I have an application_folder which will contain my flask app and its routes, etc. application_folder has a folder called dash_application. dash_application folder contains dash_example.py as below:
##########################
import glob
from pathlib import Path
from dash import Dash
import dash_table
import dash_html_components as html
import dash_core_components as dcc
import pandas as pd
from .layout import html_layout
from flask_login import login_required
def dash_application():
# Create a Dash app
dash_app = Dash(__name__,
server=False, # Don't give dash a server just yet.
url_base_pathname='/dashapp/')
# Create Dash Graph
dash_app.layout = html.Div([
html.H1('Dash application'),
dcc.Graph(
id='basic-graph',
figure={
'data':[
{
'x': [0, 1],
'y': [0, 1],
'type': 'line'
}
],
'layout': {
'title': 'Basic Graph'
}
}
)
])
return dash_app
##########################
The application_folder has my init file as:
#############################################
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_required
from .dash_application import dash_example
## Globally accessible libraries
db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = 'auth_bp.login'
dash = dash_example.dash_application()
def create_app():
# Initialize the core application.
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('config.Config')
# Initialize Plugins
db.init_app(app)
login_manager.init_app(app)
# This is where a dash app attaches to a server
dash.init_app(app=app)
with app.app_context():
# Set global variables
# Include our Routes
from . import routes
from . import auth
# Register Blueprints
app.register_blueprint(auth.auth_bp)
app.register_blueprint(routes.main_bp)
db.create_all()
return app
############################################
application_folder also has routes.py
###############################
import os
from flask import Blueprint, render_template, redirect, url_for
from flask_login import current_user, login_required
main_bp = Blueprint('main_bp', __name__,
template_folder='templates',
static_folder='static')
@main_bp.route('/')
@login_required
def home():
return render_template("index.html")
@main_bp.route('/page2')
@login_required
def home2():
return "This is page 2"
####################################
application_folder also has auth.py
###################################
import os
from flask import Blueprint, render_template, redirect, url_for, request
from flask_login import current_user, login_required, login_user, logout_user
from werkzeug.urls import url_parse
from .models import User
from .forms import LoginForm
from . import db
auth_bp = Blueprint('auth_bp', __name__,
template_folder='templates',
static_folder='static')
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('main_bp.home'))
form = LDAPLoginForm()
if form.validate_on_submit():
login_user(user=form.user)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('main_bp.home')
return redirect(next_page)
return render_template('login.html', title='Sign In', form=form)
@auth_bp.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for("auth_bp.login"))
##########################################
The route for the dash app (/dashapp/) as specified in the dash_example.py file is currently not protected from unauthorized user sessions. I need to protect that route like I have done for ‘/’ and ‘/page2’.
Before the dash 1.0 update, I could call the protect_views function and pass the dash application to it. Since it had a server at that point, the function would protect that route. Now, with the update, the dash app doesn’t get a server until the init_app is called on it. This happens in my init file as part of the factory pattern. After dash gets a flask server, I do not see the url_base_pathname attribute of the dash instance anymore. So that function doesn’t work anymore.
I simply want to be able to protect the view functions on the dash app itself. Any help would be appreciated.