# Making a 'login required' decorator
TIP
List of all code changes made in this lecture: https://diff-store.com/diff/section13__05_login_required_decorator (opens new window)
Earlier this section we wrote a simple check in our /protected
endpoint which acted as a gate for logged-out users.
If the user is not logged in, they are redirected to the login page. Otherwise, the rest of the route runs as normal.
This is such a common thing to do, that it's likely almost all your endpoints will have a check like that one:
@app.get("/protected")
def protected():
if not session.get("email"):
abort(401)
return render_template("protected.html")
# Writing the decorator
A decorator in Python is a function that acts on another function, extending it by running some code either before or after it.
I'd recommend learning about decorators in depth[1] before continuing!
Here's what our decorator looks like:
def login_required(route):
@functools.wraps(route)
def route_wrapper(*args, **kwargs):
if session.get("email") is None:
return redirect(url_for("login"))
return route(*args, **kwargs)
return route_wrapper
And this is how we use it:
@app.get("/protected")
+@login_required
def protected():
return render_template("protected.html")
With that, the protected
function is replaced by the route_wrapper
function (although it keeps its name and docstring, if any):
def route_wrapper(*args, **kwargs):
if session.get("email") is None:
return redirect(url_for("login"))
return route(*args, **kwargs)
Note that route(*args, **kwargs)
is calling what was previously the protected
function. What we've done is extracted the log in check so that any of our endpoints can be decorated with @login_required
so the check runs before anything else does in the endpoint.