Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Counting login attempts in Flask

I'm a total newbie to web development, and here is what I've tried:

@app.route('/login', methods=['GET', 'POST'])
def login():
    attempt = 0
    form = LoginForm()
    if form.validate_on_submit():
        flash('Login requested for OpenID="%s", remember_me=%s' %
              (form.openid.data, str(form.remember_me.data)))
        return redirect('/index')
    attempt += 1
    flash('Attempt(s)="%d"' % attempt)
    return render_template('login.html',
                           title='Sign In',
                           form=form)

The output is always Attempt(s)="1", while I expect the number to increase by 1 each time form.validate_on_submit() fails.

I observed that when I press Sign In button, login page is refreshed. However, all text I inputted in the text fields remained there, so I suppose form = LoginForm() wasn't executed.(If a brand new LoginForm is created, how can these text still be there?) Thus I put the statement attempt = 0 above form = LoginForm(), hoping it not to be executed each time Sign In is pressed, but apparently this does't work.

I think the problem is that I don't know what happened when I pressed Sign In. Is the function login called again? If so, it's called by whom?

Here is the content of login.html:

{% extends "base.html" %}

{% block content %}
  <h1>Sign In</h1>
  <form action="" method="post" name="login">
      {{ form.hidden_tag() }}
      <p>
          Please enter your OpenID:<br>
          {{ form.openid(size=80) }}<br>
      </p>
      <p>{{ form.remember_me }} Remember Me</p>
      <p><input type="submit" value="Sign In"></p>
  </form>
{% endblock %}
like image 786
nalzok Avatar asked Jan 06 '23 14:01

nalzok


2 Answers

The web is stateless. Every time you press a submit button, your browser calls the URL associated with that form; that URL is routed to your login() handler function, which runs from the start. The function itself has no memory of previous calls (and nor would you want it to, otherwise all users of your site would get the same login count). The form is populated from the data sent in the submit request, which is sent automatically to the form instantation by the flask-wtf library.

You need to store that count somewhere between calls. A good place to do that is in a cookie; Flask includes the sessions API to make this simpler.

like image 60
Daniel Roseman Avatar answered Jan 15 '23 11:01

Daniel Roseman


I have tried this and it worked

@app.route('/',methods=['GET'])
def home():
    session['attempt'] = 5
@app.route('/login')
def login():
    username = request.form.get('username')
    session['username'] = username
    password = request.form.get('password')
    if username and password and username in users and users[username] == password:
        session['logged_in'] = True
        return redirect(url_for('index'))
    attempt= session.get('attempt')
    attempt -= 1
    session['attempt']=attempt
    #print(attempt,flush=True)
    if attempt==1:
        client_ip= session.get('client_ip')
        flash('This is your last attempt, %s will be blocked for 24hr, Attempt %d of 5'  % (client_ip,attempt), 'error')
    else:
        flash('Invalid login credentials, Attempts %d of 5'  % attempt, 'error')
    return redirect(url_for('login'))
like image 41
Mantej Singh Avatar answered Jan 15 '23 13:01

Mantej Singh