Part 6 - Creating a web application with Flask - Sessions and restricting access

in #utopian-io7 years ago (edited)


Thanks to @oups for the image!

I've recently created my own web application using Flask and had some trouble with a few things, so once I figured them out, I thought I might as well make a tutorial series so others don't have to run into the same problems as myself! In this tutorial we will go through how to store information about a user, how to hide and show content depending on if a user is logged in or not, how to log a user out and how to restrict a user's access.


What will I learn

  • How to store information about a user
  • How to hide and show content
  • How to log a user out
  • How to restrict a user's access

Requirements

  • Python2 or Python3.3+

Difficulty

  • Intermediate

Tutorial

If you find it easier to follow along this way you can get the entire code for this tutorial from here, where I have split everything up into the relevant sections.

Logging in and sessions

In the next step we need to use session which will allow us to store information specific to a user from one request to the next. To do this we can import session from Flask (just like render_template). Once we've done this we can use this to save information about the user once we have confirmed they are in the database and their password is correct. It's very important to know if a user is logged in for example, so we can just set the one of the session's keys to True and check this if we want to see if a user is logged in or not. After saving all the information we need we should redirect them to the homepage, and as you know we can use the redirect function for this. Let's implement everything! Simply add this to our login() function

if sha512_crypt.verify(password, fetched_password):
    # So we know if a user is logged in or not
    session["logged_in"] = True
    # Save their name so we can display it when they are logged in
    session["name"] = name

    # Redirect the user
    return redirect(url_for("feed"))

Let's also make sure the buttons in navbar.html are actually working and take us to register.html and login.html by changing their href attributes to equal {{ url_for('register') }} and {{ url_for('login') }} respectively. It would also be nice if clicking "steemit" would take us to index.html, so add that as well by wrapping it in <a href="{{ url_for('index') }}">steemit</a>.

Hiding and showing content

When a user is logged in we don't want to show them the "Login" and "Sign up" buttons, as that doesn't make any sense. We also don't want to show a user someone's feed when they aren't actually logged in either. Since we have now created a session, we can check the "logged_in" key and either show or hide content based on its value! Let's start with hiding the buttons in the navbar if a user is logged in or not, and instead show their username. To do this we can simply add an if else statement to our navbar.html, as shown below

{% if session.logged_in %}
  {{ session.name }}
{% else %}
<a class="btn btn-outline-primary mr-md-3" href="{{ url_for('register') }}">Sign up</a>
<a class="btn btn-outline-primary" href="{{ url_for('login') }}">Login</a>
{% endif %}

which results in the following navbar

logged_in.png

Logging out

Before we continue we should also add the ability for a user to log out. If a user logs out, all we have to do is clear their session and then either redirect them to index.html or login.html (whichever you prefer). To do this we can add the following code to app.py

@app.route("/logout")
def logout():
    # Clear the user's session, it's that easy
    session.clear()
    # Redirect the user
    return redirect(url_for("index"))

Let's also add a button to navbar.html that allows the user to log out by clicking it, instead of having to manually navigate to /logout.

{% if session.logged_in %}
  {{ session.name }}
  <a class="btn btn-outline-primary ml-md-3" href="{{ url_for('logout') }}">Logout</a>
{% else %}

Since it returns the URL for the logout function it also calls that function, which clears the user's session, causing them to log out!

Restricting access

For some pages we would want the user to be logged in, so we need to restrict access if a user isn't logged in. To do this we can use view decorators, which is explained thoroughly here. Let's import everything they import and take their login_required() function and adapt it to suit our needs! So instead of the example they give

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if g.user is None:
            return redirect(url_for('login', next=request.url))
        return f(*args, **kwargs)
    return decorated_function

we should have the following code. Here we check if a user is logged in, and if they are, we allow them to see the page they are trying to access. If that's not the case, we redirect them to the login page, since they need to do that before they can see what they want to see

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        # If user is logged in, then allow them to see content
        if "logged_in" in session:
            return f(*args, **kwargs)
        # Otherwise redirect them to the login page!
        return redirect(url_for("login"))
    return decorated_function

To use this function to restrict access to a certain page we can simply add the decorator @login_required in between the route and the function that returns the template, like so

@app.route("/feed")
@login_required
def feed():
    return render_template("feed.html", posts=posts)

Now if we try to access /feed without loggin in we will be redirected to the login page!

Congratulations, you've now learned how to store information about a user, how to hide and show content depending on if a user is logged in or not, how to log a user out and how to restrict a user's access.

Curriculum


The code for this tutorial can be found on GitHub!

In the next tutorial we will find out how to add dynamic variables to routes, retrieve a user from your database, display their information and use Font Awesome's icons.



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

@amosbastian, I always try to support who contribute to open source project, upvote you.

Hey @amosbastian I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Coin Marketplace

STEEM 0.16
TRX 0.13
JST 0.027
BTC 60701.29
ETH 2637.06
USDT 1.00
SBD 2.52