Search code examples
pythonflask

Flask & Jinja2 if statement always evaluating to False


I am implementing an admin page on my website, but even if I enter the corect credentials it still says "No Access"

app.py:

@app.route('/login')
def login():
    return render_template('login.html', incorrect=False)

@app.route('/login', methods=['POST'])
def login_post():
    creds = dict(request.form)
    if creds['username'] == USERNAME and creds['password'] == PASSWORD:
        return redirect(url_for('admin', authenticated=1))
    else:
        return render_template('login.html', incorrect=True)

@app.route('/admin')
def admin(authenticated=0):
    conn = sqlite3.connect('articles.db')
    cur = conn.cursor()
    cur.execute("SELECT * FROM PENDING")
    articles = cur.fetchall()
    #print(articles)
    conn.close()
    return render_template('admin.html', authenticated=authenticated, articles=articles)

Note: the credentials are both admin (set in .env file)

login.html:

{% extends "base.html" %}

{% block title %}Login{% endblock %}
{% block content %}
<div class="write container py-3 mx-auto bg-muted text-white" style="width: 60vw;">
    <h1 action="{{ url_for('write_post') }}" data-aos="fade-up">Admin Login</h1>
    {% if incorrect %}
        <div class="alert alert-danger alert-dismissible">
            <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
            <strong>Incorrect Credentials</strong> Please try again.
        </div>
    {% endif %}
    <form method="POST" enctype=multipart/form-data>
        <label data-aos="fade-up" data-aos-delay="50" for="username">Username:</label><br>
            <input data-aos="fade-up" data-aos-delay="100" required maxlength="255" id="username" name="username"><br><br>
        <label data-aos="fade-up" data-aos-delay="150" for="password">Password:</label><br>
            <input data-aos="fade-up" data-aos-delay="200" required maxlength="255" id="password" name="password"><br><br>
        <input data-aos="fade-up" data-aos-delay="450" class="btn btn-success" type="submit">
    </form>
</div>
{% endblock %}

admin.html:

{% extends "base.html" %}

{% block title %}Admin{% endblock %}

{% block content %}
{% if authenticated %}
<div data-aos="fade-down" class=".container p-5 bg-muted text-white">
    <h1>Articles pending review: </h1>
</div>
{% else %}
<div data-aos="fade-down" class=".container p-5 bg-muted text-white">
    <h1>No Access</h1>
    <p>You are not logged in!</p>
</div>
{% endif %}
{% endblock %}

In app.py, even though I passed 1, the if authenticated in admin.html evaluates to false. The url is http://127.0.0.1:5001/admin?authenticated=1 The flask server was run with flask run --debug --port 5001 How do I fix this and show the content of the admin page if logged in?


Solution

  • You are passing the authenticated parameter to the admin route. When you redirect from the login_post function, you're not passing the authenticated parameter correctly.

    In your login_post function, when redirecting to the admin route upon successful login, you need to pass the authenticated parameter as part of the URL query string. Here's how you can do it:

    from flask import request, redirect, url_for
    
    @app.route('/login', methods=['POST'])
    def login_post():
        creds = dict(request.form)
        if creds['username'] == USERNAME and creds['password'] == PASSWORD:
            return redirect(url_for('admin', authenticated=1))  # Passing authenticated=1
        else:
            return render_template('login.html', incorrect=True)
    

    With this, when the login is successful, it will redirect to the admin page with the authenticated parameter set to 1.

    Also, it seems like you're using a default argument for authenticated in your admin route. This isn't necessary since you're already passing it explicitly. You can modify your admin route:

    @app.route('/admin')
    def admin():
        authenticated = request.args.get('authenticated', default=0, type=int)
        if authenticated:
            conn = sqlite3.connect('articles.db')
            cur = conn.cursor()
            cur.execute("SELECT * FROM PENDING")
            articles = cur.fetchall()
            conn.close()
            return render_template('admin.html', authenticated=authenticated, articles=articles)
        else:
            return render_template('admin.html', authenticated=authenticated)
    

    This should work.