How to merge Flask login with a Dash application?
Asked Answered
D

3

14

I have to design a web-app that provides Flask services and Dash services. For example I would like to create a login in Flask, combined with a Dash application. The problem is that I can't bind the flask login with dash. I would need a method like '@require_login' that filters access to even Dash services. The code is as follows:

app_flask = Flask(__name__)

app_flask.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////login.db'
app_flask.config['SECRET_KEY'] = 'thisissecret'

db = SQLAlchemy(app_flask)
login_manager = LoginManager()
login_manager.init_app(app_flask)

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(30), unique=True)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

@app_flask.route('/')
def index():
    user = User.query.filter_by(username='admin').first()
    login_user(user)
    return 'You are now logged in!'

@app_flask.route('/logout')
@login_required
def logout():
    logout_user()
    return 'You are now logged out!'

@app_flask.route('/home')
@login_required
def home():
    return 'The current FLASK user is ' + current_user.username

# TODO how to add login_required for dash? 
app_dash = Dash(server=app_flask, url_base_pathname='/dash/')
app_dash.layout = html.H1('MY DASH APP')


if __name__ == '__main__':
    app_dash.run_server(debug=True)
Despair answered 12/9, 2018 at 2:11 Comment(0)
U
23

This line, app_dash = Dash(server=app_flask, url_base_pathname='/dash/'), creates new view_functions in app_flask identified by its url_base_pathname.

You can debug and inspect the value of app_flask.view_functions before and after the creation of app_dash.

Now that we know which view_functions are created by app_dash, we can apply login_required to them manually.

for view_func in app_flask.view_functions:
    if view_func.startswith(app_dash.url_base_pathname):
        app_flask.view_functions[view_func] = login_required(app_flask.view_functions[view_func])
The `app_dash` endpoints will now be protected.
Unwatched answered 9/1, 2019 at 17:11 Comment(5)
SALUTE TO YOU! IT WORKSBacitracin
Doesn't work anymore: community.plot.ly/t/…Hawkinson
Replacing app_dash.url_base_pathname with app_dash.config['url_base_pathname'] works. Thanks for this solution. +1Swain
Spent 2 days working on this problem and this solution worked for me. Thanks!!!!Agnomen
This solution worked 99% perfect. Thank you! With Dash v2.1.0, I had to modify slightly: Suggest to change "app_dash.url_base_pathname" to "app_dash.config['routes_pathname_prefix']"Perorate
G
7

It would be better if you block all requests by using @app.before_request, and only allow the request if logged in or if the endpoint is marked as public.

def check_route_access():
    if request.endpoint is None:
        return redirect("/login")
 
    func = app.view_functions[request.endpoint]
    if (getattr(func, "is_public", False)):
        return  # Access granted

    # check if user is logged in (using session variable)
    user = session.get("user", None)
    if not user:
        redirect("/login")
    else:
        return  # Access granted```

Now all endpoints will be checked, even dash app endpoints.

Add this decorator named public_route:

def public_route(function):
    function.is_public = True
    return function

And add the decorator to the public methods, like login, error pages etc.

@public_route
@app.route("/login")
def login():
   # show/handle login page
   # call did_login(username) when somebody successfully logged in


def did_login(username):
    session["user"] = username

This way you never need the @login_required anymore because all endpoints require login unless stated otherwise by @public_route.

Geller answered 9/9, 2020 at 8:39 Comment(0)
S
1

A solution : session from flask (work with cookie)

from flask import session

it's an exemple :

@login_manager.user_loader def load_user(user_id): # I think here it's good session["uid"] = user_id return User.query.get(int(user_id))

# TODO how to add login_required for dash? if "uid" in session : app_dash = Dash(server=app_flask, url_base_pathname='/dash/') app_dash.layout = html.H1('MY DASH APP')

Seisin answered 12/9, 2018 at 6:14 Comment(3)
Thanks for the reply. In this way, however, the sessions are used out of context. "RuntimeError: Working outside of request context. This typically means that you attempted to use that functionality an active HTTP request. Consult the documentation on testing for information about how to avoid this problem. " A possible solution could be to save the session in a database. Do you think it's the best thing to do? Or am I doing something wrong?Despair
It's a solution but i think it's too much, if it's a small application maybe don'y use Flask-Login but session only ? if you want to use Flask-Login like this maybe find an another way to implement it ?Seisin
I am having the same issue. I have data captured in the flask application and I want to pass it to the dash route. The session object generates the same error as above. I have a sqlite db that I am accessing I will insert the data and then query the data back in the dash app. I can't come up with a better way?Salto

© 2022 - 2024 — McMap. All rights reserved.