REMEMBER_COOKIE_DURATION in flask is not working - python-3.x

I am trying to configure my application to expire cookies after some amount of time however they are not working as expected, my cookies don't get expired at all.
I have the following configuration in my app.py file:
from flask_login import LoginManager
from datetime import timedelta
app.config['REMEMBER_COOKIE_DURATION'] = timedelta(seconds=30)
login = LoginManager(app)
login.init_app(app)
login.login_view = 'login'
The following is my remember_me input:
<input type="checkbox" class="form-check-input" id="remember_me" name="remember_me">
<label class="form-check-label" for="remember_me">Remember me for 1 week</label>
Finally the following is my view function:
#app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return flask.redirect(flask.url_for('home'))
if flask.request.method == 'POST':
member_username = flask.request.form['member_username']
member_password = flask.request.form['member_password']
remember_me = flask.request.form.get('remember_me')
existing_user = Users.query.filter_by(username=member_username).first()
if existing_user is None or not existing_user.check_password(member_password):
flask.flash('Invalid username or password')
return flask.redirect(flask.url_for('login'))
if existing_user:
login_user(existing_user, remember=remember_me)
next_page = flask.request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = flask.url_for('home')
return flask.redirect(next_page)
return flask.render_template('login.html')
The resources I have already followed:
https://code.luasoftware.com/tutorials/flask/how-to-configure-flask-login/
https://www.youtube.com/watch?v=CRvV9nFKoPI
flask-login: Chrome ignoring cookie expiration?
What am I missing?

I had the same question and adding PERMANENT_SESSION_LIFETIME worked for me. My understanding is that both REMEMBER_COOKIE_DURATION and PERMANENT_SESSION_LIFETIME have effect on when the session expires.
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(seconds=30)

Related

Flask login/register form, error on the logic

I want to make a login/register form on my website, for that I found this script I reproduced from a tutorial, I adapted it but it still has an error.
If I login in the register form it's logging me, if I login in the login form, the webpage is reloading. I don't know why I have this issue but please help me!
#app.route('/', methods=['GET', 'POST'])
#app.route('/access', methods=['GET', 'POST'])
def access():
loginForm = LoginForm()
registerForm = RegisterForm()
if registerForm.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(registerForm.password.data)
new_user = User(username=registerForm.username.data, password=hashed_password)
login_user(new_user)
db.session.add(new_user)
db.session.commit()
return redirect(url_for('dashboard'))
elif loginForm.validate_on_submit():
user = User.query.filter_by(username=loginForm.username.data).first()
if user:
if bcrypt.check_password_hash(user.password, loginForm.password.data):
login_user(user)
db.session.add(user)
db.session.commit()
return redirect(url_for('home'))
return render_template('access.html', loginform=loginForm, registerform=registerForm)
You are adding your users with your login form when you use the db.session.add() and db.session.commit() functions.
This is what your login page should look like:
elif loginForm.validate_on_submit():
user = User.query.filter_by(username=loginForm.username.data).first()
if user and bcrypt.check_password_hash(user.password, loginForm.password.data):
login_user(user)
return redirect(url_for('home'))
i don't know if it works, i have an other error :
ValueError: invalid literal for int() with base 10: 'None'
there is my code :
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))

Trying to update entry but getting error "Bad Request The browser (or proxy) sent a request that this server could not understand."

I'm new to python and Flask, I'm having an issue with updating a field entry, I can add 2 fields in a user profile and saves data to their user page, also I'm able to delete that entry, but when trying to update the "Tips" field, it comes back as a 'Bad Request' error; files are:
app.py:
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField
from flask_sqlalchemy import SQLAlchemy
from forms import RegistrationForm, LoginForm, InstrumentForm, IdeasForm
from werkzeug.urls import url_parse
from werkzeug.security import generate_password_hash, check_password_hash
from wtforms import StringField, SubmitField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length
from flask_login import LoginManager, UserMixin, current_user, login_user, logout_user, login_required
from flask_bootstrap import Bootstrap
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///Mix_Tips.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config["TEMPLATES_AUTO_RELOAD"] = True
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key= True)
username = db.Column(db.String(15), index =True, unique = True)
email = db.Column(db.String(150), index = True, unique = True)
password_hash = db.Column(db.String(200))
idea = db.relationship('Ideas', backref='author', lazy='dynamic')
def __repr__(self):
return '<User {}>'.format(self.username)
return '<N'
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password_hash(self, password):
return check_password_hash(self.password_hash, password)
class Tips(db.Model):
Instrument = db.Column(db.String(50), primary_key = True)
Frequency_Boost = db.Column(db.String(200), index =True, unique=True)
Frequency_Cut = db.Column(db.String(200), index =True, unique = True)
Advice = db.Column(db.String(500))
class Ideas(db.Model):
id = db.Column(db.Integer, primary_key = True)
Instrument = db.Column(db.String(50))
Tips = db.Column(db.String(200))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<Tricks {}>'.format(self.Tips)
#app.route('/', methods=["GET", "POST"])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and user.check_password_hash(form.password.data):
login_user(user, remember=form.remember_me.data)
return redirect(url_for('user', username = form.username.data))
if user is None or not user.check_password_hash(form.password.data):
flash('Invalid username or password')
return render_template('login.html', form=form)
#app.route('/register', methods=["GET", "POST"])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('Congratulations, you are now a registered user!')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)
#app.route('/user/<username>', methods=["GET", "POST"])
#login_required
def user(username):
user = current_user
user = User.query.filter_by(username=user.username).first()
idea = Ideas.query.filter_by(user_id=user.id)
if idea is None:
idea = []
form = IdeasForm()
if request.method == 'POST' and form.validate():
New_Idea = Ideas(Instrument = form.Instrument.data, Tips = form.Tips.data, user_id=current_user.id)
db.session.add(New_Idea)
db.session.commit()
print(request.form.get('Tips'))
return render_template('user.html', user=user, form=form, idea=idea)
#app.route('/update/<int:id>', methods=['POST', 'GET'])
def update(id):
tip_to_update = Ideas.query.get_or_404(id)
if request.method == 'POST':
tip_to_update.Tips = request.form['Tips']
db.session.commit()
return redirect(url_for('user', username=current_user))
else:
return render_template('update.html', tip_to_update=tip_to_update)
#app.route('/delete/<int:id>')
def delete(id):
idea_to_delete = Ideas.query.get_or_404(id)
try:
db.session.delete(idea_to_delete)
db.session.commit()
return redirect(url_for('user', username=current_user))
except:
return "Problem Deleting"
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('login'))
**user.html:**
{% extends 'base.html' %}
{% block content %}
<center><h1 style="color:rgb(41, 15, 135)">Welcome back {{current_user.username }}!</h1></center>
<center><h2 style="color:rgb(41, 15, 135)">Music Mixing Guide</h2></center>
<h3 style="color:rgb(69, 67, 67)">Add your Instrument and Specific Tips for Mixing below:</h3>
<form action="user" method='POST'>
{{ form.hidden_tag() }}
<p
style="color:rgb(52, 52, 52)">{{form.Instrument.label}} <br>
{{form.Instrument(size=30)}}
</p>
<p
style="color:rgb(52, 52, 52)">{{form.Tips.label}} <br>
{{form.Tips(size=80)}}
</p>
<p> <input class="btn btn-outline-dark" type="submit" value="Add"></p>
</form>
<br>
<h3>Your Music Mixing Tips</h3>
{% for tricks in idea %}
<ol>
<li><p style="color:rgb(41, 15, 135)"> <b><h5>Instrument:</h5></b> {{tricks.Instrument}}</li>
<p style="color:rgb(41, 15, 135)"> <b><h5>Tip:</h5></b> {{tricks.Tips}}
</ol>
<p></p> Update
Delete
<br>
{% endfor %}
<br>
<br>
<br>
Log Out
{% endblock %}
**update.html:**
{% extends 'base.html' %}
{% block content %}
<div class='container'></div>
<h2>Update Mix Tip</h2>
<br>
<form action="/update/{{tip_to_update.id}}" method="POST">
<input type="text" placeholder="Tip" Tips="Tips" class="form-control" value="{{tip_to_update.Tips}}"> <br> <br>
<input type="submit" value="Update" class="btn btn-secondary btn-sm">
</form>
</div>
{% endblock %}
**forms.py**
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length
from flask_sqlalchemy import SQLAlchemy
class RegistrationForm(FlaskForm):
username=StringField('Username', validators=[DataRequired(), Length(min=4, max=15)])
email=StringField('Email', validators=[DataRequired(), Email(message='Invalid Email'), Length(max=150)])
password=PasswordField('Password', validators=[DataRequired(), Length(min=4, max=150)])
Repeat_password=PasswordField('Repeat Password', validators=[DataRequired(), EqualTo('password')])
submit=SubmitField('Register')
class LoginForm(FlaskForm):
username=StringField('Username', validators=[DataRequired(), Length(min=4, max=15)])
password=PasswordField('Password', validators=[DataRequired(), Length(min=4, max=150)])
remember_me=BooleanField('Remember Me')
submit=SubmitField('Sign In')
class InstrumentForm(FlaskForm):
Instrument= SelectField('Instrument', choices=[('Voice'), ('Acoustic Guitar'), ('Electric Guitar'),
('Bass Guitar'), ('Piano'), ('Bass Drum'), ('Snare Drum'), ('HiHats'), ('Toms'), ('Cymbals'), ('Brass')])
class IdeasForm(FlaskForm):
Instrument = StringField('Instrument')
Tips = StringField('Tips')
submit= SubmitField('Add')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user is not None:
raise ValidationError('Please use a different username.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user is not None:
raise ValidationError('Please use a different email address.')
I think it may have something to do with the "request.form['Tips'] line in app.py, but would like to know for sure and how to fix it.
Thanks
welcome mac. I'm not sure the error message, but as far as i can tell you'll need to rework your database models, your relationships to be precised. Here is an example:
class Ideas(db.Model):
id = db.Column(db.Integer, primary_key = True)
instrument = db.Column(db.String(50))
tips = db.relationship("Tips", lazy="dynamic")
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
have a look at the docs: https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/
also i recomment this flask mega tutorial from Miguel Grinberg: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
Thanks for the advice , I finally found out what was wrong , the "tip_to_update.Tips = request.form['Tips']" line in the update route should be "tip_to_update.Tips = form.Tips.data" instead , as I used the Flask Form method of collecting data in my register route, it wasn't accepting the request.form method. I'm still unable to show the data entered in the placeholder when a user wants to update a Tip, it opens the update page with a empty placeholder field to update , but I'd like the text from the entered tip to show , so the user can make a few alterations instead of typing out the whole tip again.

Field validation in WTF Forms Flask, redirect method

I am trying to create my first Flask web application and found the following problem, I have two pages, the first page should take players names and give the names to the next page, but unfortunately name validation does not work due to some reason, I can keep the required fields empty and go to next page with empty names fields.
Flask code:
class ChooseName(FlaskForm):
first_player_name = StringField("Choose first player name: ", [DataRequired()])
second_player_name = StringField("Choose second player name: ", [DataRequired()])
button = SubmitField("Confirm")
#app.route('/')
def index():
form = ChooseName()
if form.validate_on_submit():
return redirect(url_for('mega'))
return render_template('TIC_TAC_TOE_index.html', form=form)
#app.route('/game_page', methods=["GET", "POST"])
def mega():
player1 = request.args.get('first_player_name')
player2 = request.args.get('second_player_name')
......
return render_template('mega.html', form=form, error=error, x=x,
turn=turn,tornado=tornado, renew=renew, player1=player1,player2=player2)
HTML template:
<form action="{{url_for('mega')}}" method="get">
{{ form.hidden_tag() }}
<h4>Please choose players names!</h4>
{{form.first_player_name.label}} {{form.first_player_name}} <br> <br>
{{form.second_player_name.label}} {{form.second_player_name}} <br> <br>
{{form.button}} <br> <br>
</form>
Well looking at your function Mega(), you're not returning anything on the next page. You're just accepting the input but aren't returning it in any form.
from wtforms import Form, StringField, validators, SubmitField
from flask_wtf import FlaskForm
from flask import Flask, render_template, request
class ChooseName(FlaskForm):
first_player_name = StringField("Choose first player name: ", [validators.DataRequired()])
second_player_name = StringField("Choose second player name: ", [validators.DataRequired()])
button = SubmitField("Confirm")
app = Flask(__name__)
app.config['SECRET_KEY'] = "IT_IS_SECRET"
#app.route('/')
def index():
form = ChooseName()
if form.validate_on_submit():
return redirect(url_for('mega'))
return render_template('TIC_TAC_TOE_index.html', form=form)
#app.route('/game_page', methods=["GET", "POST"])
def mega():
player1 = request.args.get('first_player_name')
player2 = request.args.get('second_player_name')
return player1 + ' ' + player2
if __name__ == '__main__':
app.run(port=5000,debug=True)
Try to run this code, I hope this helps. :-)
This is because your action is pointing to the mega view, so the code from index if form.validate_on_submit(): is not being executed.
You should change the action attribute and method in your form. The code should be as follows:
HTML template:
<form action="" method="post">
{{ form.hidden_tag() }}
<h4>Please choose players names!</h4>
{{form.first_player_name.label}} {{form.first_player_name}} <br> <br>
{{form.second_player_name.label}} {{form.second_player_name}} <br> <br>
{{form.button}} <br> <br>
</form>
Views:
from flask import session
#app.route('/')
def index():
form = ChooseName()
if form.validate_on_submit():
session['first_player_name'] = form.first_player_name.data
session['second_player_name'] = form.second_player_name.data
return redirect(url_for('mega'))
return render_template('TIC_TAC_TOE_index.html', form=form)
#app.route('/game_page', methods=["GET", "POST"])
def mega():
player1 = session.pop('first_player_name')
player2 = session.pop('second_player_name')
......
return render_template('mega.html', form=form, error=error, x=x,
turn=turn,tornado=tornado, renew=renew, player1=player1,player2=player2)
You can learn more about WTForms here https://j2logo.com/tutorial-flask-leccion-3-formularios-wtforms/

How to redirect users to the required html page only after successful login (Flask Python App)?

I am trying to set up login page before accessing any other page. So as of now the code is working fine but if I access '/home' its taking directly to that page without login required page.
I tried to understand online solutions like login-required with SQLAlchemy but nothing seems working and I got totally lost. This does not require login-required I guess.
Here's my code:
from dbscriptdeploy import dbupdate
from flask.templating import render_template
from flask import Flask, request, url_for, redirect
DBupdate = dbupdate()
app = Flask(__name__) #create the Flask app
#app.route('/success')
def deploy_success():
return render_template("success.html")
def deploy_script(sql):
res = DBupdate.dbvalues_get(sql)
return res
#app.route('/', methods=['GET', 'POST'])
def login_page():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
error = 'Invalid Credentials. Please try again.'
else:
return redirect(url_for('form_example'))
return render_template('login.html', error=error)
#app.route('/home', methods=['GET', 'POST'])
def form_example():
res = None
error = ''
try:
if request.method == 'POST':
sql = request.form.get('sql')
res = deploy_script(sql)
if res:
return redirect(url_for('deploy_success'))
else:
error = "*Invalid Value. Please try again."
return render_template('home.html', error=error)
except Exception as e:
return render_template('home.html', error=error)
if __name__ == '__main__':
app.run(debug=True) #run app in debug mode on port 5000
Login.html Code:
<html>
<head>
<title>Flask Intro - login page</title>
</head>
<body>
<div class="container">
<h1>Please login</h1>
<br>
<form action="" method="post">
<input type="text" placeholder="Username" name="username" value="{{
request.form.username }}">
<input type="password" placeholder="Password" name="password" value="{{
request.form.password }}">
<input class="btn btn-default" type="submit" value="Login">
</form>
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}
{% endif %}
</div>
</body>
</html>
So what I expect is after successful login only then they should be directed to \home page else they should be directed again to login page.
If I were you, I'd use flask-login. However, if you want to develop a simple solution by your own, you should save some var in the user's session.
Also in your login method there is a bug. I'd do:
from flask import session
#app.route('/', methods=['GET', 'POST'])
def login_page():
error = None
if request.method == 'POST':
if request.form['username'] == 'admin' and request.form['password'] == 'admin':
session['admin'] = request.form['username']
return redirect(url_for('form_example'))
else:
error = 'Invalid Credentials. Please try again.'
return render_template('login.html', error=error)
Then, in your form_example view you should check that admin is in session, else you can redirect to your login view:
#app.route('/home', methods=['GET', 'POST'])
def form_example():
if 'admin' not in session:
return redirect(url_for('login_page'))
else:
# Your code here
If you really want to go down the path of developing your own login/authentication solution, check out the documentation for flash_message
http://flask.pocoo.org/docs/1.0/patterns/flashing/. This tutorial has the exact problem you're tackling.
The re-routing of a successful login attempt occurs with the redirect call
return redirect(url_for('homepage'))

Flask login using Linux System Credentials

I am creating a simple web app using flask. I will be hosting it on my linux server.
The web-app does multiple user specific things. Like list directories in Users home, add ssh-keys for user and stuff like that.
I would like to know if there is a way for flask to open a login page, and the user-name and password be validated based on system user-name and password. (i.e that users system credentials). If yes, then how. If no then what else can I do?
Using ’simplepam’ python package you can authenticate against PAM system on linux. Here is flask basic example which I have modifed to use simplepam:
from flask import Flask, session, redirect, url_for, escape, request
from simplepam import authenticate
app = Flask(__name__)
#app.route('/')
def index():
if 'username' in session:
return 'Logged in as %s' % escape(session['username'])
return 'You are not logged in'
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if authenticate(str(username), str(password)):
session['username'] = request.form['username']
return redirect(url_for('index'))
else:
return 'Invalid username/password'
return '''
<form action="" method="post">
<p><input type=text name=username>
<p><input type=password name=password>
<p><input type=submit value=Login>
</form>
'''
#app.route('/logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
# set the secret key. keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
if __name__ == '__main__':
app.run(debug='True')

Resources