pythonflaskflask-httpauth

Default login_required rather than adding decorator everywhere


I'm using Flask-HTTPAuth to handle authentication in my app. I have a lot of views, and I don't want to add login_required to every one of them. How can I make login required by default?

from flask.ext.httpauth import HTTPBasicAuth
auth = HTTPBasicAuth()

@auth.verify_password
def verify_password(username, password):
    return username == '111' and password == '222'

@app.route('/')
@app.route('/home/')
@auth.login_required
def index():
    return 'Hello'

@app.route('/route2/')
def route2():
    return 'route2'

app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'

Solution

  • You can add a before_request function to require login by default, and create a simple login_exempt decorator for the few routes that don't require it.

    Make sure to exempt static files, otherwise they won't load for unauthenticated users.

    Flask-HTTPAuth's login_required doesn't have a way to separate the require logic from the view decorator, you need to go through a little dance to require auth without running a view.

    def login_exempt(f):
        f.login_exempt = True
        return f
    
    # a dummy callable to execute the login_required logic
    login_required_dummy_view = auth.login_required(lambda: None)
    
    @app.before_request
    def default_login_required():
        # exclude 404 errors and static routes
        # uses split to handle blueprint static routes as well
        if not request.endpoint or request.endpoint.rsplit('.', 1)[-1] == 'static':
            return
    
         view = current_app.view_functions[request.endpoint]
    
         if getattr(view, 'login_exempt', False):
             return
    
         return login_required_dummy_view()
    
    # for example, the login page shouldn't require login
    @app.route('/login', methods=['GET', 'POST'])
    @login_exempt
    def login():
        pass