79

In the before_request() function (below), I want to redirect the user to /login if they are not yet logged in. Is there a special variable that will give me the current URL that will work as the below example does?

@app.before_request
def before_request():
    # the variable current_url does not exist
    # but i want something that works like it
    if (not 'logged_in' in session) and (current_url != '/login'):
        return redirect(url_for('login'))

I need to check that the current URL is /login, because if I don't the server goes into an infinite loop.

amitchone
  • 1,630
  • 3
  • 21
  • 45
SeanPlusPlus
  • 8,663
  • 18
  • 59
  • 84

3 Answers3

109

There are a couple of properties on the request object you can check, documented here, request.path is probably what you want. Can I suggest request.endpoint though, so you'll be covered should you decide to route your view to another url, or multiple urls

@app.before_request
def before_request():
    if 'logged_in' not in session and request.endpoint != 'login':
        return redirect(url_for('login'))
davidism
  • 121,510
  • 29
  • 395
  • 339
DazWorrall
  • 13,682
  • 5
  • 43
  • 37
  • 1
    I am trying to do something really similar and are indeed trying to use request.endpoint, but what I have discovered is that that property shows up only on two of my routes ('/' and '/about/'). For all other routes, request.endpoint is None and when inspecting the request object, url_rule doesn't even exist? All my routes are defined the same way with the app.router decorator. Any ideas what could be going on? Thanks for any help – RobertoCuba Jun 26 '15 at 21:34
  • I needed to add `and request.endpoint != 'static'` to get this working correctly under the dev server of the latest flask dev code – Mike Nov 24 '15 at 14:57
  • +1 for checking whether the endpoint of the request is 'login', or else some redirect loop will occur. :-) – andy May 08 '16 at 12:20
  • If anyone wonders what the deal with endpoints is, this is a good explanation on Flask routing: https://stackoverflow.com/a/19262349/593487 – johndodo Sep 08 '18 at 07:38
  • Note, to access the actual function, you can do so using `current_app.view_functions[request.endpoint]`. This way one can implement `@auth_exempt` decorator that'd set an attribute on a view function, and a `before_request` handler that would check for this attribute. – drdaeman May 21 '20 at 02:45
24

You can use a decorator. Here's an example that shows how to check an API key before specific requests:

from functools import wraps

def require_api_key(api_method):
    @wraps(api_method)

    def check_api_key(*args, **kwargs):
        apikey = request.headers.get('ApiKey')
        if apikey and apikey == SECRET_KEY:
            return api_method(*args, **kwargs)
        else:
            abort(401)

    return check_api_key

And you can use it with:

@require_api_key
amitchone
  • 1,630
  • 3
  • 21
  • 45
savepopulation
  • 11,736
  • 4
  • 55
  • 80
12

Here's an implementation of the accepted answer with flask-login:

@app.before_request
def require_authorization():
    from flask import request
    from flask.ext.login import current_user

    if not (current_user.is_authenticated or request.endpoint == 'login'):
        return login_manager.unauthorized()
Ryne Everett
  • 6,427
  • 3
  • 37
  • 49
  • could you please look into this..? https://stackoverflow.com/questions/58885706/aiohttp-before-request-for-each-api-call – Anant Nov 21 '19 at 16:52