Flask: how to register a wrapper to all methods
You can definitely some of the functionality of flask-httpauth yourself, if you wish :-P
I would think you will need to play some before_request
games (not very beautiful), or alternatively call flask's add_url_rule
with a decorated method for each api endpoint (or have a route
decorator of your own that will do this). The add_url_rule
gets a view function that is usually your api endpoint handler, but in your case, will be a wrapped method in a manner very much like the one you gave in the post (auth_middleware
).
The gist of it:
from flask import Flask, make_response, request
app = Flask(__name__)
def view_wrapper(fn):
"""
Create a wrapped view function that checks user authorization
"""
def protected_view(*a, **ka):
# if the allow_anonymous annotation is set then bypass this auth
if hasattr(fn, '_allow_anonymous') and fn._allow_anonymous:
return fn(*a, **ka)
# consult werkzeug's authorization mixin
user, password = (request.authorization.username, request.authorization.password) if request.authorization else (None, None)
if user is None or not check(user, password):
err_response = make_response(text, 401)
err_response.headers['WWW-Authenticate'] = 'Basic realm="%s"' % realm
return err_response
return fn(*a, **ka)
return protected_view
# An endpoint
def hello():
return 'hello there'
app.add_url_rule('/', 'hello', view_wrapper(hello))
Of course, this can (and should) be further enhanced with Blueprints, etc.
Note #1: this is cribbed from separate answers in SO.
Note #2: this doesnt use blueprints. Again, I'm new to flask and I appreciate that blueprints will help the app scale but one step at a time...
def allow_anonymous(decorated_function):
decorated_function.is_public = True
return decorated_function
@app.before_request
def auth_middleware():
fn = app.view_functions[request.endpoint]
if hasattr(fn, 'allow_anonymous') and fn.allow_anonymous:
# anonymous permitted
return
elif my_custom_authentication():
# anonymous not permitted authentication succeeded
return
else:
# anonymous not permitted authentication failed
err_response = make_response(text, 401)
err_response.headers['WWW-Authenticate'] = 'Basic realm="%s"' % realm
return err_response
@app.route('/public_thing')
@allow_anonymous
def public_thing():
return 'yo'
@app.route('/regular_thing')
def regular_thing():
return 'if you can read this youre authenticated.'