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.'

Tags:

Flask

Bottle