Skip to content

Instantly share code, notes, and snippets.

@xapple
Created September 5, 2018 07:52
Show Gist options
  • Save xapple/bb8fe6a2adca9cbf86675cb48b59f0be to your computer and use it in GitHub Desktop.
Save xapple/bb8fe6a2adca9cbf86675cb48b59f0be to your computer and use it in GitHub Desktop.
"""
This submodule is inspired from the dash-flask-login library at:
https://github.com/gaw89/dash-flask-login
It is unlicensed.
To implement this in your dash app, add this file auth.py to your superproject
and do something like this in your server script:
from superproject.auth import FlaskLoginAuth
server = Flask("superproject")
app = Dash(name='superproject', server=server, url_base_pathname='/')
users = [('steven', 'vc98zq23jkhjyxcvoi')]
auth = FlaskLoginAuth(app, users=users)
Be sure to create /assets/login.html with a log-in form for it to work.
"""
# Modules #
import os, hashlib, flask
# Flask #
from flask import request, redirect, url_for
from flask_login import login_required, LoginManager, UserMixin, login_user
###############################################################################
class DefaultUser(UserMixin):
def __init__(self, name, password, hash_function):
self.id = name.lower()
self.username = name.lower()
self.password = hash_function(password)
def __eq__(self, other):
return self.id == other.id
###############################################################################
class UserMap(object):
def __init__(self, users):
"""*users* is a list of DefaultUser objects"""
self.users = users
self.user_map = {}
for u in self.users: self.user_map.update({u.id: u})
def get_user(self, id):
try: return self.user_map[id]
except: return None
###############################################################################
class FlaskLoginAuth():
def __init__(self, app, users):
"""
app: A Dash object to be login-protected
users: Should be a list of tuples of the format (<USERNAME>, <PASSWORD>)
where each element is a unicode string.
This will be used to create a list of DefaultUser objects.
"""
# Basic attributes #
self.server = app.server
# Users #
self.users = UserMap([DefaultUser(u[0], u[1], self.hash_function) for u in users])
# Alter the view functions of the server to require login #
self.server.view_functions['/view'] = login_required(self.server.view_functions['/view'])
# Setup the LoginManager for the server #
self.login_manager = LoginManager()
self.login_manager.init_app(self.server)
self.login_manager.login_view = "/login"
# Secret Key #
self.server.config.update(SECRET_KEY = os.urandom(12))
# Callback to reload the user object #
@self.login_manager.user_loader
def load_user(userid):
return self.users.get_user(userid)
# The default templates #
current_directory = os.path.dirname(os.path.abspath(__file__))
self.login_html = current_directory + '/assets/login.html'
# Rule #
self.server.add_url_rule(
'/login',
view_func = self.default_login_view,
methods = ['GET', 'POST']
)
# Base route goes to login #
@self.server.route('/', methods=['GET'])
def save():
return redirect(url_for('default_login_view'))
def hash_function(self, string):
return hashlib.md5().update(string.encode('utf-8')).hexdigest()
def default_login_view(self):
if request.method == 'POST':
username = request.form['username'].lower()
password = request.form['password']
password = self.hash_function(password)
user = self.users.get_user(username)
if user:
if password == user.password:
login_user(user)
return redirect(flask.url_for('/view'))
return flask.send_file(self.login_html)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment